using System;
using System.Collections.Generic;
using System.Text;
using GTANetworkAPI;
using ReallifeGamemode.Database.Entities;
using ReallifeGamemode.Database.Models;
using ReallifeGamemode.Server.Extensions;
using ReallifeGamemode.Server.Managers;
using ReallifeGamemode.Server.Services;

namespace ReallifeGamemode.Server.Util
{
  class Rentcar : Script
  {
    //In Sekunden
    public static int PAY_TIMER = 180;

    //In Stunden
    private static int PAYTIME_FREE = GlobalHelper.newbiePlayedMinutesThreshold / 60;

    public static List<RentcarProperty> noobspawnVehicleProperties = new List<RentcarProperty>();
    private static Vector3 noobspawnVehicleSpawnPosition = new Vector3(-1020.18695, -2695.2253, 13.988778);
    private static double noobspawnVehicleSpawnHeading = 151.39877;
    public static Vector3 noobSpawnBlipPosition = new Vector3(-1023.3046, -2694.8992, 13.906858);

    public static List<RentcarProperty> stadthalleVehicleProperties = new List<RentcarProperty>();
    private static Vector3 stadthalleVehicleSpawnPosition = new Vector3(-373, -236.31334, 35.8506);
    private static double stadthalleVehicleSpawnHeading = 109.96821;
    public static Vector3 stadthalleBlipPosition = new Vector3(-369.7236, -231.82654, 35.993023);

    public static List<RentcarProperty> knastVehicleProperties = new List<RentcarProperty>();
    private static Vector3 knastVehicleSpawnPosition = new Vector3(1212.741, 2726.6135, 38.00415);
    private static double knastVehicleSpawnHeading = 173.14825;
    public static Vector3 knastBlipPosition = new Vector3(1220.3483, 2725.4932, 38.00414);

    public static List<RentcarProperty> paletoVehicleProperties = new List<RentcarProperty>();
    private static Vector3 paletoVehicleSpawnPosition = new Vector3(-216.75778198242188, 6215.0068359375, 31.490657806396484);
    private static double paletoVehicleSpawnHeading = -133.99148559570312;
    public static Vector3 paletoBlipPosition = new Vector3(-214.52447509765625, 6218.1708984375, 31.49131965637207);

    public static List<RentcarProperty> lamesaVehicleProperties = new List<RentcarProperty>();
    private static Vector3 lamesaVehicleSpawnPosition = new Vector3(811.4766235351562, -1041.594482421875, 26.58707618713379);
    private static double lamesaVehicleSpawnHeading = 88.71146392822266;
    public static Vector3 lamesaBlipPosition = new Vector3(818.3075561523438, -1039.78759765625, 26.750783920288086);

    public static Dictionary<string, (Vehicle, int)> mapPlayerRentcarBill = new Dictionary<string, (Vehicle, int)>();

    public static void Setup()
    {
      noobspawnVehicleProperties.Add(new RentcarProperty("bmx", 10));
      noobspawnVehicleProperties.Add(new RentcarProperty("faggio3", 50));

      stadthalleVehicleProperties.Add(new RentcarProperty("bmx", 10));
      stadthalleVehicleProperties.Add(new RentcarProperty("faggio3", 50));

      knastVehicleProperties.Add(new RentcarProperty("bmx", 10));
      knastVehicleProperties.Add(new RentcarProperty("faggio3", 50));

      paletoVehicleProperties.Add(new RentcarProperty("bmx", 10));
      paletoVehicleProperties.Add(new RentcarProperty("faggio3", 50));

      lamesaVehicleProperties.Add(new RentcarProperty("bmx", 10));
      lamesaVehicleProperties.Add(new RentcarProperty("faggio3", 50));
    }

    public static void cancelRent(Player player)
    {
      using (var dbContext = new DatabaseContext())
      {
        User user = player.GetUser(dbContext);
        user.BankAccount.Balance -= mapPlayerRentcarBill[player.Name].Item2;
        dbContext.SaveChanges();
      }

      player.SetData("hasRentcar", false);
      player.TriggerEvent("abortRentcarTimer");
      player.SendChatMessage("~y~[Fahrzeugverleih] ~w~Mietfahrzeug erfolgreich gekündigt (Kosten: ~g~$~w~" + mapPlayerRentcarBill[player.Name].Item2 + ").");
      VehicleManager.DeleteVehicle(mapPlayerRentcarBill[player.Name].Item1);
      Rentcar.mapPlayerRentcarBill.Remove(player.Name);
    }

    [RemoteEvent("SERVER:updateRentCarBill")]
    public void updateRentCarBill(Player player, int bill, int time)
    {
      if (canRentForFree(player))
      {
        return;
      }

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

        if (bill > user.BankAccount.Balance)
        {
          ChatService.ErrorMessage(player, "Du hast nicht genügend Geld auf dem Konto. Dein Mietfahrzeug wurde zurückgegeben");
          cancelRent(player);
          dbContext.SaveChanges();
          return;
        }
        dbContext.SaveChanges();
      }

      if (!mapPlayerRentcarBill.ContainsKey(player.Name))
      {
        return;
      }
      
      player.TriggerEvent("BN_Show", "Fahrzeug seit ~b~" + (int)(time / 60) + "~w~ Minuten gemietet (Gesamtkosten: ~g~$~s~" + bill + ").");
      mapPlayerRentcarBill[player.Name] = (mapPlayerRentcarBill[player.Name].Item1, bill);      
    }

    [RemoteEvent("SERVER:rentcarBooked")]
    public void rentcarBooked(Player player, string vehicleName, int price, String rentcarLocation)
    {
      if (player.GetData<bool>("hasRentcar") == true)
      {
        ChatService.ErrorMessage(player, "Du hast bereits ein Fahrzeug gemietet. Mit '/rent stop' kündigst du deinen bisherigen Mietvertrag");
        return;
      }

      if (!uint.TryParse(vehicleName, out uint uHash))
        uHash = NAPI.Util.GetHashKey(vehicleName);

      if (!VehicleManager.IsValidHash(uHash))
      {
        return;
      }

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

        if (price > user.BankAccount.Balance)
        {
          ChatService.ErrorMessage(player, "Du hast nicht genügend Geld auf dem Konto");
          dbContext.SaveChanges();
          return;
        }
        dbContext.SaveChanges();
      }
      Vehicle v = null;

      if (rentcarLocation == "noobspawn")
      {
        v = NAPI.Vehicle.CreateVehicle(uHash, noobspawnVehicleSpawnPosition, (float)noobspawnVehicleSpawnHeading, 111, 111, engine: true);
      }
      else if (rentcarLocation == "stadthalle")
      {
        v = NAPI.Vehicle.CreateVehicle(uHash, stadthalleVehicleSpawnPosition, (float)stadthalleVehicleSpawnHeading, 111, 111, engine: true);
      }
      else if (rentcarLocation == "knast")
      {
        v = NAPI.Vehicle.CreateVehicle(uHash, knastVehicleSpawnPosition, (float)knastVehicleSpawnHeading, 111, 111, engine: true);
      }
      else if (rentcarLocation == "paleto")
      {
        v = NAPI.Vehicle.CreateVehicle(uHash, paletoVehicleSpawnPosition, (float)paletoVehicleSpawnHeading, 111, 111, engine: true);
      }
      else if (rentcarLocation == "lamesa")
      {
        v = NAPI.Vehicle.CreateVehicle(uHash, lamesaVehicleSpawnPosition, (float)lamesaVehicleSpawnHeading, 111, 111, engine: true);
      }

      if (v == null)
      {
        return;
      }

      VehicleStreaming.SetEngineState(v, true);
      VehicleStreaming.SetLockStatus(v, false);

      mapPlayerRentcarBill[player.Name] = (v, 0);

      player.SendChatMessage("~y~[Fahrzeugverleih] ~w~Viel Spaß mit deinem Fahrzeug! Mit '/rent stop' kannst du den Mietvertrag kündigen.");

      if (canRentForFree(player))
      {
        player.SendChatMessage("~y~[Fahrzeugverleih] ~w~Da du neu in der Stadt bist, wird dir diese Fahrt nicht in Rechnung gestellt.");
      }

      player.SetData("hasRentcar", true);
      player.TriggerEvent("triggerRentcarTimer", PAY_TIMER, price);
    }
    public static bool canRentForFree(Player player)
    {
      bool ret = false;

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

        if (user.PlayedMinutes < PAYTIME_FREE * 60)
        {
          ret = true;
        }

        dbContext.SaveChanges();
      }

      return ret;
    }
  }
}
