using GTANetworkAPI;
using Newtonsoft.Json;
using ReallifeGamemode.Server.Business;
using ReallifeGamemode.Server.Entities;
using ReallifeGamemode.Server.Extensions;
using ReallifeGamemode.Server.Models;
using ReallifeGamemode.Server.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ReallifeGamemode.Server.Managers
{
    class BusinessManager : Script
    {
        public static List<BusinessBase> Businesses { get; private set; }

        public static void LoadBusinesses()
        {
            Businesses = new List<BusinessBase>();

            IEnumerable<Type> allTypes = Assembly.GetExecutingAssembly().GetTypes().Where(type => type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(BusinessBase)));
            foreach (Type item in allTypes)
            {
                NAPI.Util.ConsoleOutput($"Loading Business {item.Name}");
                if (Activator.CreateInstance(item) is BusinessBase o)
                {
                    if (GetBusiness(o.Id) != null)
                    {
                        throw new InvalidOperationException($"Double Business ID found: {o.Id} | {o.Name}");
                    }
                    Businesses.Add(o);
                    o.Setup();
                    o.Load();
                    o.Update();
                }
            }
        }

        public static T GetBusiness<T>() where T : BusinessBase
        {
            return (T)Businesses.Find(b => b.GetType() == typeof(T));
        }

        public static BusinessBase GetBusiness(int? id)
        {
            return Businesses.Find(b => b.Id == id);
        }

        [RemoteEvent("Business_DepositMoney")]
        public void BusinessDepositMoney(Client player, int amount)
        {
            User user = player.GetUser();
            if (user == null)
            {
                return;
            }

            BusinessBase playerBusiness = GetBusiness(user.BusinessId);

            TransactionResult result = BankManager.TransferMoney(user, playerBusiness, amount, "Überweisung");

            /*if(result == TransactionResult.NEGATIVE_MONEY_SENT)
            {
                player.SendNotification("~r~Es können nur positive Beträge überwiesen werden");
                return;
            }
            else if(result == TransactionResult.SENDER_NOT_ENOUGH_MONEY)
            {
                player.SendNotification("~r~Du hast nicht genug Geld");
                return;
            }
            else */
            if (result == TransactionResult.SUCCESS)
            {
                player.TriggerEvent("business_updateMoney", playerBusiness.GetBankAccount().Balance.ToMoneyString());
                player.SendNotification("~g~Du hast erfolgreich ~s~" + amount.ToMoneyString() + " ~g~ überwiesen");
                return;
            }
        }

        [RemoteEvent("Business_WithdrawMoney")]
        public void BusinessWithdrawMoney(Client player, int amount)
        {
            User user = player.GetUser();
            if (user == null)
            {
                return;
            }

            BusinessBase playerBusiness = GetBusiness(user.BusinessId);

            TransactionResult result = BankManager.TransferMoney(playerBusiness, user, amount, "Überweisung");

            if (result == TransactionResult.NEGATIVE_MONEY_SENT)
            {
                player.SendNotification("~r~Es können nur positive Beträge überwiesen werden");
                return;
            }
            else if (result == TransactionResult.SENDER_NOT_ENOUGH_MONEY)
            {
                player.SendNotification("~r~Es ist nicht genug Geld auf der Businesskasse vorhanden");
                return;
            }
            else if (result == TransactionResult.SUCCESS)
            {
                player.TriggerEvent("business_updateMoney", playerBusiness.GetBankAccount().Balance.ToMoneyString());
                player.SendNotification("~g~Du hast erfolgreich ~s~" + amount.ToMoneyString() + " ~g~ überwiesen");
                return;
            }
        }

        [ServerEvent(Event.PlayerEnterVehicle)]
        public void CarDealerBusiness_PlayerEnterVehicle(Client player, Vehicle veh, int seat)
        {
            ServerVehicle sVeh = veh.GetServerVehicle();
            if (sVeh == null) return;
            if (!(sVeh is ShopVehicle)) return;
            ShopVehicle shopVehicle = (ShopVehicle)sVeh;

            List<string> availableTargets = new List<string>()
            {
                "Spieler"
            };

            if (player.GetUser().FactionLeader && !player.GetUser().Faction.StateOwned) availableTargets.Add("Fraktion");
            if (player.GetUser().GroupRank == GroupRank.OWNER) availableTargets.Add("Gruppe");

            player.TriggerEvent("ShopVehicle_OpenMenu", GetBusiness(shopVehicle.BusinessId).Name, shopVehicle.Price, availableTargets.ToArray());
        }

        [RemoteEvent("VehShop_BuyVehicle")]
        public void CarDealerBusiness_BuyVehicle(Client player, string target)
        {
            ServerVehicle sVeh = player.Vehicle?.GetServerVehicle();
            if (sVeh == null) return;
            if (!(sVeh is ShopVehicle)) return;
            ShopVehicle shopVehicle = (ShopVehicle)sVeh;
            int price = shopVehicle.Price;
            CarDealerBusinessBase business = GetBusiness(shopVehicle.BusinessId) as CarDealerBusinessBase;
            TransactionResult result = BankManager.TransferMoney(player.GetUser(), business, price, "Auto gekauft");
            if (result == TransactionResult.SENDER_NOT_ENOUGH_MONEY)
            {
                player.SendNotification("~r~Du hast nicht genug Geld: " + price.ToMoneyString());
                return;
            }

            Vector3 spawnPos = business.CarSpawnPositon.Around(3);

            player.TriggerEvent("SERVER:Util_setWaypoint", spawnPos.X, spawnPos.Y);

            ServerVehicle newVeh = null;

            if(target == "Spieler")
            {
                 newVeh = new UserVehicle
                 {
                     Heading = business.CarSpawnHeading,
                     PositionX = spawnPos.X,
                     PositionY = spawnPos.Y,
                     PositionZ = spawnPos.Z,
                     Locked = false,
                     UserId = player.GetUser().Id,
                     Model = shopVehicle.Model,
                     PrimaryColor = 111,
                     SecondaryColor = 111,
                     Active = true,
                 };
            }
            else if(target == "Fraktion")
            {
                newVeh = new FactionVehicle
                {
                    Heading = business.CarSpawnHeading,
                    PositionX = spawnPos.X,
                    PositionY = spawnPos.Y,
                    PositionZ = spawnPos.Z,
                    Locked = false,
                    FactionId = player.GetUser().FactionId,
                    Model = shopVehicle.Model,
                    PrimaryColor = 111,
                    SecondaryColor = 111,
                    Active = true,
                };
            }
            else if(target == "Gruppe")
            {
                newVeh = new GroupVehicle
                {
                    Heading = business.CarSpawnHeading,
                    PositionX = spawnPos.X,
                    PositionY = spawnPos.Y,
                    PositionZ = spawnPos.Z,
                    Locked = false,
                    GroupId = player.GetUser().Group.Id,
                    Model = shopVehicle.Model,
                    PrimaryColor = 111,
                    SecondaryColor = 111,
                    Active = true,
                };
            }

            using (var dbContext = new DatabaseContext())
            {
                dbContext.ServerVehicles.Add(newVeh);
                dbContext.SaveChanges();
            }

            newVeh.Spawn();
        }
    }
}
