using GTANetworkAPI;
using Newtonsoft.Json;
using ReallifeGamemode.Database.Entities;
using ReallifeGamemode.Server.Extensions;
using ReallifeGamemode.Server.Inventory;
using ReallifeGamemode.Server.Inventory.Interfaces;
using ReallifeGamemode.Server.Services;
using ReallifeGamemode.Server.Util;
using System;
using System.Timers;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ReallifeGamemode.Database.Models;
using ReallifeGamemode.Services;

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

namespace ReallifeGamemode.Server.Managers
{
  public class InventoryManager : Script
  {
    public static List<IItem> itemList;

    private static Dictionary<int, (int[], int[])> TradeItems { get; set; } = new Dictionary<int, (int[], int[])>();
    private static Dictionary<int, Timer> TradeTimer { get; set; } = new Dictionary<int, Timer>();
    private static Dictionary<int, int> TradeValue { get; set; } = new Dictionary<int, int>();


    public static void LoadItems()
    {
      itemList = new List<IItem>();

      Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes();
      foreach (Type item in allTypes)
      {
        if (item.GetInterfaces().Contains((typeof(IItem))) && !item.IsAbstract)
        {
          NAPI.Util.ConsoleOutput($"Loading Item {item.Name}");
          if (Activator.CreateInstance(item) is IItem o)
          {
            if (GetItemById(o.Id) != null)
            {
              throw new InvalidOperationException($"Double ItemID found: {o.Id} | {o.Name}");
            }
            itemList.Add(o);
          }
        }
      }
    }

    public static IItem GetItemById(int id)
    {
      return itemList.Find(i => i.Id == id);
    }

    public static IItem GetItemByName(string name)
    {
      return itemList.Find(i => i.Name.ToLower() == name.ToLower());
    }

    public static void RemoveUserItem(User user, UserItem item, int amount)
    {
      using (var dbContext = new DatabaseContext())
      {
        var userItem = dbContext.UserItems.FirstOrDefault(i => i.Id == item.Id);

        userItem.Amount -= amount;

        dbContext.SaveChanges();

        if (userItem.Amount == 0)
        {
          dbContext.Remove(userItem);
          dbContext.SaveChanges();
        }
      }
    }

    public static void GetUserItems(Player player)
    {
      var user = player.GetUser();
      var inventoryWeight = 0;
      List<string> iName = new List<string>();
      List<int> iAmount = new List<int>();
      List<int> iId = new List<int>();
      List<int> iWeight = new List<int>();

      using (var context = new DatabaseContext())
      {
        List<UserItem> userItems = context.UserItems.ToList().FindAll(i => i.UserId == user.Id);


        foreach (var item in userItems)
        {
          IItem iItem = GetItemById(item.ItemId);
          var currentItemWeight = iItem.Gewicht * item.Amount;
          inventoryWeight += currentItemWeight;

          iName.Add(iItem.Name);
          iAmount.Add(item.Amount);
          iId.Add(iItem.Id);

        }
        List<Player> targetList = NAPI.Player.GetPlayersInRadiusOfPlayer(2, player);
        List<string> username = new List<string>();
        foreach (var target in targetList)
        {
          User cl = target.GetUser();
          username.Add(cl.Name);
        }

        player.TriggerEvent("inventoryShow", inventoryWeight, iName.ToArray(), iAmount.ToArray(), iId.ToArray(), username.ToArray());
      }
    }

    public static int GetUserInventoryWeight(Player player)
    {
      var user = player.GetUser();
      var inventoryWeight = 0;

      using (var context = new DatabaseContext())
      {
        List<UserItem> userItems = context.UserItems.ToList().FindAll(i => i.UserId == user.Id);
        foreach (var item in userItems)
        {
          IItem iItem = GetItemById(item.ItemId);
          var currentItemWeight = iItem.Gewicht * item.Amount;
          inventoryWeight += currentItemWeight;
        }
      }

      return inventoryWeight;
    }


    public static int GetVehicleInventoryWeight(Vehicle veh)
    {
      var inventoryWeight = 0;

      using (var context = new DatabaseContext())
      {
        ServerVehicle serverVehicle = VehicleManager.GetServerVehicleFromVehicle(veh, context);
        List<VehicleItem> vehItems = context.VehicleItems.ToList().FindAll(i => i.VehicleId == serverVehicle.Id);
        foreach (var item in vehItems)
        {
          IItem iItem = GetItemById(item.ItemId);
          var currentItemWeight = iItem.Gewicht * item.Amount;
          inventoryWeight += currentItemWeight;
        }
      }

      return inventoryWeight;
    }

    public static UserItem UserHasThisItem(Player player, int itemId)
    {
      var user = player.GetUser();
      using (var context = new DatabaseContext())
      {
        UserItem existingItem = context.UserItems.FirstOrDefault(i => i.UserId == user.Id && i.ItemId == itemId);
        return existingItem;
      }
    }

    public static void GetUserItemsAsAdmin(Player player, User user)
    {
      var inventoryWeight = 0;

      using (var context = new DatabaseContext())
      {
        List<UserItem> userItems = context.UserItems.ToList().FindAll(i => i.UserId == user.Id);
        string[][] items = new string[userItems.Count][];
        foreach (var item in userItems)
        {
          IItem iItem = GetItemById(item.ItemId);
          var currentItemWeight = iItem.Gewicht * item.Amount;
          inventoryWeight += currentItemWeight;

          items[userItems.IndexOf(item)] = new string[6];
          items[userItems.IndexOf(item)][0] = iItem.Name;
          items[userItems.IndexOf(item)][1] = iItem.Description;
          items[userItems.IndexOf(item)][2] = iItem.Gewicht.ToString();
          items[userItems.IndexOf(item)][3] = item.Amount.ToString();
          items[userItems.IndexOf(item)][4] = item.Slot.ToString();
          items[userItems.IndexOf(item)][5] = item.Id.ToString();
        }
        player.TriggerEvent("showInventoryToAdmin", user.Name, inventoryWeight, items);
      }
    }

    public bool CheckOriginOfItem(Player client, string jsonItemID, string jsonItemAmount, string jsonOrigin, string jsonVehAmount)
    {
      var origin = JsonConvert.DeserializeObject<int[]>(jsonOrigin);
      var itemID = JsonConvert.DeserializeObject<int>(jsonItemID);
      var itemAmount = JsonConvert.DeserializeObject<int>(jsonItemAmount);
      var vehAmount = JsonConvert.DeserializeObject<int>(jsonVehAmount);
      var user = client.GetUser();
      using (var context = new DatabaseContext())
      {
        if (origin.Length < 1)
          return false;


        if (origin[0] == 1)
        {
          foreach (Vehicle veh in NAPI.Pools.GetAllVehicles())
          {
            if (veh.Position.DistanceTo(client.Position) < 5f)
            {
              if (VehicleStreaming.GetDoorState(veh, DoorID.DoorTrunk) == DoorState.DoorOpen || VehicleStreaming.GetDoorState(veh, DoorID.DoorRearLeft) == DoorState.DoorOpen || VehicleStreaming.GetDoorState(veh, DoorID.DoorRearRight) == DoorState.DoorOpen)
              {

                UserItem vItem = new UserItem
                {
                  Amount = vehAmount,
                  ItemId = itemID,
                  UserId = user.Id,
                  Slot = -1
                };

                ServerVehicle serverVehicle = VehicleManager.GetServerVehicleFromVehicle(veh, context);
                VehicleItem vehItem = context.VehicleItems.Where(v => v.VehicleId == origin[1] && v.ItemId == vItem.ItemId).FirstOrDefault();
                if (vehItem != null)
                {
                  IItem iItem = GetItemById(vItem.ItemId);

                  if (GetUserInventoryWeight(client) + (iItem.Gewicht * vItem.Amount) > 40000)
                  {
                    for (int i = 0; i <= vItem.Amount; i++)
                    {
                      if (GetUserInventoryWeight(client) + (iItem.Gewicht * i) > 40000)
                      {
                        vItem.Amount = i - 1;
                        break;
                      }

                    }
                  }

                  if (vItem.Amount == 0)
                  {
                    return false;
                  }

                  if (itemAmount < vehItem.Amount)
                  {
                    UserItem uItem = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == vItem.ItemId).FirstOrDefault();
                    if (uItem == null)
                    {
                      context.Add(vItem);
                    }
                    else
                    {
                      uItem.Amount += vItem.Amount;
                    }
                    context.SaveChanges();
                    return true;
                  }
                  else if (itemAmount == vehItem.Amount)
                  {
                    UserItem uItem = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == vItem.ItemId).FirstOrDefault();
                    if (uItem == null)
                    {
                      context.Add(vItem);
                    }
                    else
                    {
                      uItem.Amount += vItem.Amount;
                    }
                    context.SaveChanges();
                    return true;
                  }
                  return false;
                }
              }
            }
          }
        }
        else if (origin[0] == 0)
        {

          VehicleItem cItem = new VehicleItem
          {
            Amount = vehAmount,
            ItemId = itemID,
            VehicleId = origin[1],
            Slot = -1,
          };

          UserItem uItem = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == cItem.ItemId).FirstOrDefault();
          IItem iItem = GetItemById(cItem.ItemId);
          Vehicle veh = VehicleManager.GetVehicleFromId(cItem.VehicleId);
          if (GetVehicleInventoryWeight(veh) + (iItem.Gewicht * cItem.Amount) > 250000)
          {
            for (int i = 0; i <= cItem.Amount; i++)
            {
              if (GetVehicleInventoryWeight(veh) + (iItem.Gewicht * i) > 250000)
              {
                cItem.Amount = i - 1;
                break;
              }

            }
          }

          if (cItem.Amount == 0)
          {
            return false;
          }

          if (iItem is IWeaponDealItem weaponDealItem)
          {
            return false;
          }

          if (uItem != null)
          {
            if (vehAmount < uItem.Amount)
            {

              VehicleItem vehItem = context.VehicleItems.Where(v => v.VehicleId == cItem.VehicleId && v.ItemId == cItem.ItemId).FirstOrDefault();
              if (vehItem == null)
              {
                context.Add(cItem);
              }
              else
              {
                vehItem.Amount += cItem.Amount;
              }
              context.SaveChanges();
              return true;


            }
            else if (vehAmount == uItem.Amount)
            {
              VehicleItem vehItem = context.VehicleItems.Where(v => v.VehicleId == cItem.VehicleId && v.ItemId == cItem.ItemId).FirstOrDefault();
              if (vehItem == null)
              {
                context.Add(cItem);
              }
              else
              {
                vehItem.Amount += cItem.Amount;
              }
              context.SaveChanges();
              return true;
            }
            return false;
          }
        }
        return false;
      }
    }

    [RemoteEvent("saveVehicleInventory")]
    public void SaveVehicleInventory(Player player, string jsonItemID, string jsonItemAmount, string jsonGotFrom, string vehAmount)
    {
      var itemID = JsonConvert.DeserializeObject<int>(jsonItemID);
      var itemAmount = JsonConvert.DeserializeObject<int>(jsonItemAmount);
      var origin = JsonConvert.DeserializeObject<int[]>(jsonGotFrom);

      if (!CheckOriginOfItem(player, jsonItemID, jsonItemAmount, jsonGotFrom, vehAmount))
        return;

      using (var context = new DatabaseContext())
      {

        VehicleItem vItem = new VehicleItem
        {
          Amount = itemAmount,
          ItemId = itemID,
          VehicleId = origin[1],
          Slot = -1
        };

        VehicleItem vehItem = context.VehicleItems.Where(v => v.VehicleId == vItem.VehicleId && v.ItemId == vItem.ItemId).FirstOrDefault();
        if (vehItem == null)
        {
          context.VehicleItems.Add(vItem);
        }
        else if (vItem.Amount <= 0)
        {
          context.VehicleItems.Remove(vehItem);
        }
        else
        {
          vehItem.Amount = vItem.Amount;
        }
        context.SaveChanges();
        IItem iItem = GetItemById(vItem.ItemId);
        player.TriggerEvent("aproveTransfer", JsonConvert.DeserializeObject<int>(vehAmount), iItem.Name, "Rucksack");
      }
    }


    [RemoteEvent("saveInventory")]
    public void SavePlayerInventory(Player player, string jsonItemID, string jsonItemAmount, string jsonGotFrom, string vehAmount)
    {

      var user = player.GetUser();
      var itemID = JsonConvert.DeserializeObject<int>(jsonItemID);
      var itemAmount = JsonConvert.DeserializeObject<int>(jsonItemAmount);
      var origin = JsonConvert.DeserializeObject<int[]>(jsonGotFrom);

      if (!CheckOriginOfItem(player, jsonItemID, jsonItemAmount, jsonGotFrom, vehAmount))
        return;

      using (var context = new DatabaseContext())
      {

        UserItem cItem = new UserItem
        {
          Amount = itemAmount,
          ItemId = itemID,
          UserId = user.Id,
          Slot = -1,
        };


        UserItem item = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == cItem.ItemId).FirstOrDefault();
        if (item == null)
        {
          context.UserItems.Add(cItem);
        }
        else if (cItem.Amount <= 0)
        {
          context.UserItems.Remove(item);
        }
        else
        {
          item.Amount = cItem.Amount;
        }

        context.SaveChanges();
        IItem iItem = GetItemById(item.ItemId);
        player.TriggerEvent("aproveTransfer", JsonConvert.DeserializeObject<int>(vehAmount), iItem.Name, "Kofferraum");
      }
    }

    public static void AddItemToInventory(Player player, UserItem item)
    {
      var user = player.GetUser();
      using (var context = new DatabaseContext())
      {
        UserItem existingItem = context.UserItems.FirstOrDefault(i => i.ItemId == item.ItemId && i.UserId == item.UserId);
        if (existingItem != null)
        {
          existingItem.Amount += item.Amount;
        }
        else
        {
          List<UserItem> allItemsByUser = context.UserItems.ToList().FindAll(i => i.UserId == user.Id);
          var slotArr = Enumerable.Range(1, 20).ToList();
          allItemsByUser.ForEach(allItem =>
          {
            if (slotArr.Contains(allItem.Slot)) slotArr.Remove(allItem.Slot);
          });

          int newSlot = slotArr.Min();

          item.Slot = newSlot;
          context.UserItems.Add(item);

          IItem iItem = GetItemById(item.ItemId);

          string[] newItem = new string[] { iItem.Name, iItem.Description, iItem.Gewicht.ToString(), item.Amount.ToString(), newSlot.ToString(), item.Id.ToString() };

          player.TriggerEvent("addItem", JsonConvert.SerializeObject(newItem));
        }
        context.SaveChanges();
      }
    }

    public static void AddItemToVehicleInventory(Player player, VehicleItem item, Vehicle veh)
    {
      var user = player.GetUser();
      using (var context = new DatabaseContext())
      {
        ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(veh);
        VehicleItem existingItem = context.VehicleItems.FirstOrDefault(i => i.ItemId == item.ItemId && i.VehicleId == sVeh.Id);
        if (existingItem != null)
        {
          existingItem.Amount += item.Amount;
        }
        else
        {
          List<VehicleItem> allItemsByVehicle = context.VehicleItems.ToList().FindAll(i => i.VehicleId == sVeh.Id);
          var slotArr = Enumerable.Range(1, 20).ToList();
          allItemsByVehicle.ForEach(allItem =>
          {
            if (slotArr.Contains(allItem.Slot)) slotArr.Remove(allItem.Slot);
          });

          int newSlot = slotArr.Min();

          item.Slot = newSlot;
          context.VehicleItems.Add(item);

          IItem iItem = GetItemById(item.ItemId);

          string[] newItem = new string[] { iItem.Name, iItem.Description, iItem.Gewicht.ToString(), item.Amount.ToString(), newSlot.ToString(), item.Id.ToString() };
        }
        context.SaveChanges();
      }
    }

    public static void RemoveAllItemsfromVehicleInventory(Vehicle veh)
    {
      using (var context = new DatabaseContext())
      {
        ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(veh);
        List<VehicleItem> allItemsByVehicle = context.VehicleItems.ToList().FindAll(i => i.VehicleId == sVeh.Id);
        allItemsByVehicle.ForEach(allItem =>
        {
          context.Remove(allItem);
        });
        context.SaveChanges();
      }
    }

    [RemoteEvent("removeItemAsAdmin")]
    public void RemoveAsAdminInventory(Player player, string amount, string userItemId, string targetPlayerName)
    {
      using (var context = new DatabaseContext())
      {
        UserItem fItem = context.UserItems.FirstOrDefault(j => j.Id == int.Parse(userItemId));

        Player targetPlayer = PlayerService.GetPlayerByNameOrId(targetPlayerName);

        if (amount == "stack")
        {
          var itemSlot = fItem.Slot;
          targetPlayer.TriggerEvent("removeItem", userItemId, fItem.Amount);
          context.UserItems.Remove(fItem);
        }
        else if (amount == "one")
        {
          var itemSlot = fItem.Slot;
          targetPlayer.TriggerEvent("removeItem", userItemId, 1);
          fItem.Amount--;
        }
        context.SaveChanges();
      }
    }

    [RemoteEvent("itemInteract")]
    public void ItemInteract(Player player, string jsonType, string jsonAmount, string jsonItemId)
    {
      int amount = JsonConvert.DeserializeObject<int>(jsonAmount);
      int itemId = JsonConvert.DeserializeObject<int>(jsonItemId);
      string type = JsonConvert.DeserializeObject<string>(jsonType);

      User user = player.GetUser();

      using (var context = new DatabaseContext())
      {
        UserItem fItem = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == itemId).FirstOrDefault();
        IItem iItem = GetItemById(fItem.ItemId);

        switch (type)
        {
          case "use":
            if (iItem == null)
            {
              player.TriggerEvent("Error", "Dieses Essen existiert nicht.");
              return;
            }

            if (fItem == null)
            {
              player.TriggerEvent("Error", "Du hast dieses Item nicht");
              return;
            }

            if (iItem is IUsableItem usableItemObj)
            {
              usableItemObj.Use(fItem);
              player.TriggerEvent("removeItem", itemId, 1);
              player.TriggerEvent("aproveUse", 1, iItem.Name);
            }
            else player.TriggerEvent("Error", "Du kannst dieses Item nicht benutzen.");
            break;
          case "drop":

            if (iItem == null)
            {
              player.TriggerEvent("Error", "Dieses Item existiert nicht.");
              return;
            }

            if (fItem == null)
            {
              player.TriggerEvent("Error", "Du hast dieses Item nicht");
              return;
            }

            if (iItem is IDroppableItem usableItemObj2)
            {
              Vector3 dropPosition = PlayerExtension.GetPositionFromPlayer(player, 0.6f, 0);
              //new Vector3(player.Position.X, player.Position.Y, player.Position.Z - 0.8f);
              Random r = new Random();
              GTANetworkAPI.Object grndObject;
              if (iItem is IWeaponDealItem obj)
              {
                dropPosition.Z -= 1.05f;
                grndObject = NAPI.Object.CreateObject(3666746839, dropPosition, new Vector3(0, 0, r.Next(0, 360)), 0);
              }
              else
              {
                dropPosition.Z -= 0.8f;
                grndObject = NAPI.Object.CreateObject(3777723516, dropPosition, new Vector3(0, 0, r.Next(0, 360)), 0);
              }
              GroundItem grndItem = new GroundItem { ItemId = iItem.Id, Amount = amount, Position = dropPosition };
              TextLabel grndTxtLbl = NAPI.TextLabel.CreateTextLabel(iItem.Name + " ~s~(~y~" + amount + "~s~)", dropPosition, 5, 0.5f, 4, new Color(255, 255, 255), false, 0);
              GroundItem.AddGroundItem(grndItem, grndObject, grndTxtLbl);
              if (fItem.Amount > amount)
              {
                fItem.Amount -= amount;
              }
              else if (fItem.Amount == amount)
              {
                context.UserItems.Remove(fItem);
              }
              player.TriggerEvent("removeItem", itemId, amount);
              player.TriggerEvent("aproveThrow", amount, iItem.Name);
            }
            break;
        }
        context.SaveChanges();
      }
    }


    [RemoteEvent("tradeItem")]
    public void ServerEvent_tradeItem(Player client, int value, string jsonNameOrId, string itemIdArrStr, string itemAmountArrStr)
    {
      User user = client.GetUser();
      string nameOrId = JsonConvert.DeserializeObject<string>(jsonNameOrId);
      Player target = PlayerService.GetPlayerByNameOrId(nameOrId);
      if (target == null || !target.IsLoggedIn() || target == client)
      {
        ChatService.PlayerNotFound(client);
        return;
      }
      if (client.Position.DistanceTo(target.Position) >= 5)
      {
        ChatService.ErrorMessage(client, "Spieler ist zu weit entfernt.");
        return;
      }
      int[] itemIdArr = JsonConvert.DeserializeObject<int[]>(itemIdArrStr);
      int[] itemAmountArr = JsonConvert.DeserializeObject<int[]>(itemAmountArrStr);
      List<string> itemNameList = new List<string>();


      if (target.HasData("inTrade") && target.GetData<bool>("inTrade") == true)
      {
        ChatService.SendMessage(client, $"~r~[FEHLER] ~w~{target.Name} befindet sich bereits in einem Handel.");
        return;
      }
      int inventoryWeight = 0;
      using (var context = new DatabaseContext())
      {
        int targetInvWeight = GetUserInventoryWeight(target);

        for (int i = 0; i < itemIdArr.Length; i++)
        {
          int itemId = itemIdArr[i];
          int itemAmount = itemAmountArr[i];
          UserItem uitem = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == itemId).FirstOrDefault();
          IItem iItem = GetItemById(uitem.ItemId);
          var currentItemWeight = iItem.Gewicht * itemAmount;
          inventoryWeight += currentItemWeight;
        }
        if (((targetInvWeight + inventoryWeight) / 1000) > 40)
        {
          ChatService.ErrorMessage(client, "Handel kann nicht getätigt werden.");
          return;
        }

        for (int x = 0; x < itemIdArr.Length; x++)
        {
          int itemId = itemIdArr[x];
          int itemAmount = itemAmountArr[x];
          UserItem item = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == itemId).FirstOrDefault();
          if (item.Amount - itemAmount > 0)
          {
            item.Amount -= itemAmount;
          }
          else
          {
            context.UserItems.Remove(item);
          }
          IItem iItem = GetItemById(itemId);
          itemNameList.Add(iItem.Name);
          context.SaveChanges();
        }
      }
      ChatService.SendMessage(client, $"~b~Du hast eine Handelsanfrage an {target.Name} gesendet.");
      TradeItems[user.Id] = (itemIdArr, itemAmountArr);
      TradeValue[user.Id] = value;
      target.SetData("tradePartner", user.Id);
      target.SetData("trade", client.Name);
      SendTradeOffer(target, client);
      target.TriggerEvent("addTradeItems", itemIdArr, itemAmountArr, itemNameList.ToArray(), inventoryWeight);
    }

    public void SendTradeOffer(Player client, Player sender)
    {
      client.SetData("inTrade", true);
      sender.SetData("inTrade", true);
      ChatService.SendMessage(client, $"~b~ Du hast eine Handelsanfrage von {sender.Name} bekommen.");
      client.SetSharedData("tradeOffer", JsonConvert.SerializeObject(1));
      User user = sender.GetUser();
      Timer tradeTimer = new Timer(30000);
      TradeTimer[user.Id] = tradeTimer;
      tradeTimer.Start();
      tradeTimer.Elapsed += (s, e) => { SendBackToSender(sender); client.SetData("inTrade", false); sender.SetData("inTrade", false); client.SetSharedData("tradeOffer", JsonConvert.SerializeObject(0)); };
    }

    public void SendBackToSender(Player client)
    {
      User user = client.GetUser();
      ChatService.SendMessage(client, "Dein Handelspartner hat die Anfrage nicht angenommen.");
      (int[] itemIdArr, int[] itemAmountArr) = TradeItems[user.Id];
      Timer timer = TradeTimer[user.Id];
      timer.Stop();
      using (var context = new DatabaseContext())
      {
        for (int x = 0; x < itemIdArr.Length; x++)
        {
          int itemId = itemIdArr[x];
          int itemAmount = itemAmountArr[x];
          UserItem item = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == itemId).FirstOrDefault();
          if (item != null)
          {
            item.Amount += itemAmount;
          }
          else
          {
            var newItem = new UserItem
            {
              ItemId = itemId,
              UserId = user.Id,
              Amount = itemAmount,
              Slot = -1
            };

            context.UserItems.Add(newItem);
          }
          context.SaveChanges();
        }
      }
    }

    [RemoteEvent("declineTrade")]
    public void ServerEvent_declineTrade(Player client)
    {
      client.SetSharedData("tradeOffer", JsonConvert.SerializeObject(0));
      if (!client.GetData<bool>("inTrade"))
      {
        ChatService.ErrorMessage(client, "Das Handelsangebot ist abgelaufen.");
        return;
      }
      string name = client.GetData<string>("trade");
      Player target = PlayerService.GetPlayerByNameOrId(name);
      if (target == null || !target.IsLoggedIn())
      {
        ChatService.PlayerNotFound(client);
        return;
      }

      client.SetData("inTrade", false);
      target.SetData("inTrade", false);
      SendBackToSender(target);
    }

    public static void OpenTradeAccept(Player client)
    {
      User user = client.GetUser();
      int id = client.GetData<int>("tradePartner");
      (int[] itemIdArr, int[] itemAmountArr) = TradeItems[id];
      Timer tradeTimer = TradeTimer[id];
      tradeTimer.Stop();
      tradeTimer.Start();
      client.TriggerEvent("openTradeWindow", TradeValue[id], itemIdArr, itemAmountArr);
    }

    [RemoteEvent("acceptTrade")]
    public void ServerEvent_AcceptTrade(Player client)
    {
      if (!client.GetData<bool>("inTrade"))
      {
        ChatService.ErrorMessage(client, "Das Handelsangebot ist abgelaufen.");
        return;
      }
      client.SetSharedData("tradeOffer", JsonConvert.SerializeObject(0));
      client.SetData("inTrade", false);

      User user = client.GetUser();
      int id = client.GetData<int>("tradePartner");
      (int[] itemIdArr, int[] itemAmountArr) = TradeItems[id];
      Timer tradeTimer = TradeTimer[id];
      tradeTimer.Stop();
      string name = client.GetData<string>("trade");
      Player target = PlayerService.GetPlayerByNameOrId(name);
      if (target == null || !target.IsLoggedIn())
      {
        ChatService.PlayerNotFound(client);
        return;
      }
      target.SetData("inTrade", false);

      using (var context = new DatabaseContext())
      {

        int targetInvWeight = GetUserInventoryWeight(client);
        int inventoryWeight = 0;
        for (int i = 0; i < itemIdArr.Length; i++)
        {
          int itemId = itemIdArr[i];
          int itemAmount = itemAmountArr[i];
          UserItem uitem = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == itemId).FirstOrDefault();
          IItem iItem = GetItemById(uitem.ItemId);
          var currentItemWeight = iItem.Gewicht * itemAmount;
          inventoryWeight += currentItemWeight;
        }
        if (((targetInvWeight + inventoryWeight) / 1000) > 40)
        {
          ChatService.ErrorMessage(client, "Handel kann nicht getätigt werden.");
          return;
        }

        for (int x = 0; x < itemIdArr.Length; x++)
        {
          int itemId = itemIdArr[x];
          int itemAmount = itemAmountArr[x];
          UserItem item = context.UserItems.Where(u => u.UserId == user.Id && u.ItemId == itemId).FirstOrDefault();
          if (item != null)
          {
            item.Amount += itemAmount;
          }
          else
          {
            var newItem = new UserItem
            {
              ItemId = itemId,
              UserId = user.Id,
              Amount = itemAmount,
              Slot = -1
            };

            context.UserItems.Add(newItem);
          }
          context.SaveChanges();
        }
      }
      ChatService.SendMessage(target, $"{client.Name} hat deine Anfrage angenommen.");

    }

    [RemoteEvent("SERVER:BuyItems")]
    public void SrvEvent_BuyItem(Player client, string itemName)
    {
      IItem shopItem = GetItemByName(itemName);

      using(var dbContext = new DatabaseContext()){
        User user = client.GetUser(dbContext);

        if (user.Handmoney < shopItem.Price)
        {
          client.TriggerEvent("itemMenu:Error");
          return;
        } 

        UserItem item = dbContext.UserItems.Where(i => i.ItemId == shopItem.Id && i.UserId == user.Id).FirstOrDefault();
        if(item == null)
        {
          var newItem = new UserItem
          {
            ItemId = shopItem.Id,
            UserId = user.Id,
            Amount = 1,
            Slot = -1
          };
          dbContext.UserItems.Add(newItem);
        }
        else
        {
          item.Amount += 1;
        }
        user.Handmoney -= shopItem.Price;
        dbContext.SaveChanges();
        client.TriggerEvent("SERVER:SET_HANDMONEY", user.Handmoney);
      }

    }
  }
}
