using GTANetworkAPI;
using Newtonsoft.Json;
using ReallifeGamemode.Server.Entities;
using ReallifeGamemode.Server.Extensions;
using ReallifeGamemode.Server.Job;
using ReallifeGamemode.Server.Models;
using ReallifeGamemode.Server.Services;
using ReallifeGamemode.Server.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

/**
* @overview Life of German Reallife - Managers Interaction (InteractionManager.cs)
* @author VegaZ
* @copyright (c) 2008 - 2018 Life of German
*/

namespace ReallifeGamemode.Server.Managers
{
    public class InteractionManager : Script
    {
        #region Umgebungsinteraktionen PFEILTASTE-HOCH
        #endregion
        #region Eigeninteraktionen PFEILTASTE-RUNTER
        [RemoteEvent("CLIENT:InteractionMenu_AcceptInvite")]
        public void InteractionMenuAcceptInvite(Client player, string type)
        {
            if (type != "Fraktion" && type != "Gruppe") return;

            if (type == "Fraktion") // Fraktions Invite annehmen
            {
                if (!player.HasData("accept_faction_invite"))
                {
                    ChatService.ErrorMessage(player, "Du hast keine Einladung in eine Fraktion erhalten");
                    return;
                }

                Client leader = NAPI.Player.GetPlayerFromHandle((NetHandle)player.GetData("accept_faction_invite"));
                player.ResetData("accept_faction_invite");

                if (leader == null)
                {
                    ChatService.ErrorMessage(player, "Die Einladung ist abgelaufen");
                    return;
                }

                using (var dbContext = new DatabaseContext())
                {
                    User u = leader.GetUser(dbContext);
                    User own = player.GetUser(dbContext);

                    own.FactionId = u.FactionId;
                    own.FactionLeader = false;
                    own.FactionRankId = dbContext
                        .FactionRanks
                        .OrderBy(x => x.Order)
                        .Where(r => r.FactionId == own.FactionId)
                        .FirstOrDefault()?.Id ?? null;

                    ChatService.SendMessage(leader, "!{02FCFF}" + player.Name + " hat die Einladung angenommen.");
                    ChatService.SendMessage(player, "!{02FCFF}Du hast die Einladung angenommen.");

                    dbContext.SaveChanges();
                }
            }
            else if (type == "Gruppe") // Gruppen Einladung annehmen
            {
                if (!player.HasData("accept_group_invite"))
                {
                    ChatService.ErrorMessage(player, "Du hast keine Einladung in eine Gruppe erhalten");
                    return;
                }

                Client leader = NAPI.Player.GetPlayerFromHandle((NetHandle)player.GetData("accept_group_invite"));
                player.ResetData("accept_group_invite");

                if (leader == null)
                {
                    ChatService.ErrorMessage(player, "Die Einladung ist abgelaufen");
                    return;
                }

                using (var dbContext = new DatabaseContext())
                {
                    User u = leader.GetUser(dbContext);
                    User own = player.GetUser(dbContext);

                    own.Group = u.Group;
                    own.GroupRank = GroupRank.MEMBER;

                    ChatService.SendMessage(leader, "!{02FCFF}" + player.Name + " hat die Einladung angenommen.");
                    ChatService.SendMessage(player, "!{02FCFF}Du hast die Einladung angenommen.");

                    dbContext.SaveChanges();
                }
            }
        }

        [RemoteEvent("CLIENT:InteractionMenu_Invite")]
        public void InteractionMenuInviteFaction(Client player, string type, string nameOrId)
        {
            if (type != "Fraktion" && type != "Gruppe") return;

            Client target = ClientService.GetClientByNameOrId(nameOrId);
            if (target == null || !target.IsLoggedIn())
            {
                ChatService.PlayerNotFound(player);
                return;
            }

            User targetUser = target.GetUser();
            User playerUser = player.GetUser();

            if (type == "Fraktion")
            {
                if (playerUser?.FactionId == null || playerUser?.FactionLeader == false)
                {
                    ChatService.NotAuthorized(player);
                    return;
                }

                if (targetUser?.FactionId != null)
                {
                    ChatService.ErrorMessage(player, "Dieser Spieler ist schon in einer Fraktion");
                    return;
                }

                target.SetData("accept_faction_invite", player.Handle);

                ChatService.SendMessage(player, "!{02FCFF}Du hast dem Spieler " + target.Name + " eine Einladung in deine Fraktion gesendet.");
                ChatService.SendMessage(target, "!{02FCFF}Du hast von " + player.Name + " eine Einladung in die Fraktion \"" + playerUser.Faction.Name + "\" erhalten.");
                ChatService.SendMessage(target, "!{02FCFF}Benutze das Interaktionsmenü, um die Einladung anzunehmen");
            }
            else if (type == "Gruppe")
            {
                if (playerUser?.Group == null || playerUser.GroupRank < GroupRank.MANAGER)
                {
                    ChatService.NotAuthorized(player);
                    return;
                }

                if (targetUser?.Group != null)
                {
                    ChatService.ErrorMessage(player, "Dieser Spieler ist schon in einer Gruppe");
                    return;
                }

                target.SetData("accept_group_invite", player.Handle);

                ChatService.SendMessage(player, "!{02FCFF}Du hast dem Spieler " + target.Name + " eine Einladung in deine Gruppe gesendet.");
                ChatService.SendMessage(target, "!{02FCFF}Du hast von " + player.Name + " eine Einladung in die Gruppe \"" + playerUser.Group.Name + "\" erhalten.");
                ChatService.SendMessage(target, "!{02FCFF}Benutze das Interaktionsmenü, um die Einladung anzunehmen");
            }
        }

        [RemoteEvent("CLIENT:InteractionMenu_Uninvite")]
        public void InteractionMenuInviteGroup(Client player, string type, string name)
        {
            if (type != "Fraktion" && type != "Gruppe") return;

            Client target = ClientService.GetClientByNameOrId(name);
            if (target == null || !target.IsLoggedIn())
            {
                ChatService.PlayerNotFound(player);
                return;
            }

            User targetUser = target.GetUser();
            User playerUser = player.GetUser();

            if (type == "Fraktion")
            {
                if (playerUser?.FactionId == null || playerUser.FactionLeader == false)
                {
                    ChatService.NotAuthorized(player);
                    return;
                }

                if (targetUser?.FactionId != playerUser?.FactionId)
                {
                    ChatService.ErrorMessage(player, "Dieser Spieler ist nicht in deiner Fraktion");
                    return;
                }

                if (player.Handle == target.Handle)
                {
                    ChatService.ErrorMessage(player, "Du kannst dich nicht selber uninviten");
                    return;
                }

                if (targetUser?.FactionLeader ?? false)
                {
                    ChatService.ErrorMessage(player, "Du kannst keinen Leader uninviten");
                    return;
                }

                using (var dbContext = new DatabaseContext())
                {

                    target.GetUser(dbContext).FactionRankId = null;
                    target.GetUser(dbContext).FactionId = null;

                    ChatService.SendMessage(player, "!{02FCFF}Du hast " + target.Name + " aus der Fraktion geworfen.");
                    ChatService.SendMessage(target, "!{02FCFF}Du wurdest von " + player.Name + " aus der Fraktion geworfen.");

                    dbContext.SaveChanges();
                }
            }
            else if (type == "Gruppe")
            {
                if (playerUser?.Group == null || playerUser.GroupRank < GroupRank.MANAGER)
                {
                    ChatService.NotAuthorized(player);
                    return;
                }

                if (targetUser?.Group.Id != playerUser?.Group.Id)
                {
                    ChatService.ErrorMessage(player, "Dieser Spieler ist nicht in deiner Fraktion");
                    return;
                }

                if (player.Handle == target.Handle)
                {
                    ChatService.ErrorMessage(player, "Du kannst dich nicht selber uninviten");
                    return;
                }

                if (targetUser?.GroupRank >= GroupRank.MANAGER && playerUser?.GroupRank != GroupRank.OWNER)
                {
                    ChatService.ErrorMessage(player, "Du kannst keinen Leader uninviten");
                    return;
                }

                using (var dbContext = new DatabaseContext())
                {

                    target.GetUser(dbContext).Group = null;
                    target.GetUser(dbContext).GroupRank = GroupRank.NONE;

                    ChatService.SendMessage(player, "!{02FCFF}Du hast " + target.Name + " aus der Gruppe geworfen.");
                    ChatService.SendMessage(target, "!{02FCFF}Du wurdest von " + player.Name + " aus der Gruppe geworfen.");

                    dbContext.SaveChanges();
                }
            }
        }

        [RemoteEvent("CLIENT:InteractionMenu_CallService_Taxi")]
        public void CallServiceTaxi(Client player, string street, string zone)
        {
            var taxiJob = JobManager.GetJob<TaxiDriverJob>();

            if(taxiJob.TaxiContracts.Where(t => t.Name == player.Name).Count() != 0)
            {
                ChatService.ErrorMessage(player, "Du kannst nur einmal ein Taxi rufen");
                return;
            }

            taxiJob.TaxiContracts.Add(new TaxiContract()
            {
                Name = player.Name,
                Position = player.Position
            });

            string msg = $"!{{02FCFF}}{player.Name} hat in der Straße {street} in {zone} ein Taxi gerufen.";
            ChatService.BroadcastJob(msg, taxiJob);
            ChatService.SendMessage(player, "!{02FCFF}Du hast erfolgreich ein Taxi zu deiner aktuellen Position gerufen.");
        }
        #endregion
        #region Spielerinteraktionen PFEILTASTE-LINKS
        [RemoteEvent("openTradeInventory")]
        public void OpenTradeInventory(Client player, string targetPlayer)
        {
            InventoryManager.GetUserItems(player);
            player.TriggerEvent("openTradeMenu", targetPlayer);
        }

        [RemoteEvent("sendTradeItemsToPartner")]
        public void SendTradeItemsToPartner(Client player, string tradeItemArray, int tradePrize, string tradePartnerName)
        {
            var tradeItems = JsonConvert.DeserializeObject<string[][]>(tradeItemArray);
            Client tradePartner = ClientService.GetClientByNameOrId(tradePartnerName);
            InventoryManager.GetUserItems(player);
            tradePartner.TriggerEvent("showTradeRequest", player.Name, tradeItems, tradePrize);
            player.TriggerEvent("startTradeRequestTimer");
        }

        [RemoteEvent("tradeDecision")]
        public void TradeDecision(Client player, string tradeSelection, string tradeItemArray, string tradeRequesterName, int tradePrize)
        {
            var tradeItems = JsonConvert.DeserializeObject<string[][]>(tradeItemArray);
            Client tradeRequester = ClientService.GetClientByNameOrId(tradeRequesterName);
            if (tradeSelection == "accept")
            {
                if (player.GetUser().Handmoney < tradePrize)
                {
                    tradeRequester.TriggerEvent("unlockTradeItems");
                    tradeRequester.SendNotification("~y~" + player.Name + " ~r~hat nicht genügend Bargeld! ~s~Handel abgebrochen.");
                    player.SendNotification("~r~Du hast nicht genügend Bargeld! ~s~Handel abgebrochen.");
                }
                else
                {
                    InventoryManager.GetUserItems(player);
                    tradeRequester.TriggerEvent("clearTradeItems");
                    player.TriggerEvent("showTradeItems", tradeItemArray);

                    using (var dbContext = new DatabaseContext())
                    {
                        var playerUserId = player.GetUser().Id;
                        var tradeRUserId = tradeRequester.GetUser().Id;
                        var playerUser = dbContext.Users.FirstOrDefault(u => u.Id == playerUserId);
                        var tradeRequesterUser = dbContext.Users.FirstOrDefault(u => u.Id == tradeRUserId);

                        playerUser.Handmoney -= tradePrize;
                        player.TriggerEvent("SERVER:WORLD_INTERACTION:UPDATE_HANDMONEY", playerUser.Handmoney);

                        tradeRequesterUser.Handmoney += tradePrize;
                        tradeRequester.TriggerEvent("SERVER:WORLD_INTERACTION:UPDATE_HANDMONEY", tradeRequesterUser.Handmoney);

                        dbContext.SaveChanges();
                    }
                }
            }
            else
            {
                tradeRequester.TriggerEvent("unlockTradeItems");
            }
        }
        #endregion
        #region Fraktionsinteraktionen / Jobinteraktionen PFEILTASTE-RECHTS
        #endregion
    }
}
