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

namespace ReallifeGamemode.Server.Job
{
  internal class PilotJob : JobBase
  {
    public override int Id => 3;

    public override string Name => "Pilot";

    private const int CHECKPOINT_MARKER_ID = 6;

    public const string BEGINNER = "Anfänger";
    public const string INTERMEDIATE = "Fortgeschrittener";
    public const string PROFESSIONAL = "Profi";

    public const int WAGE_BEGINNER = 350;
    public const int WAGE_INTERMEDIATE = 950;

    public const uint VEHICLE_BEGINNER = (uint)VehicleHash.Cuban800;
    public const uint VEHICLE_INTERMEDIATE = (uint)VehicleHash.Velum2;
    public const uint VEHICLE_PROFESSIONAL = (uint)VehicleHash.Submersible;

    public static Dictionary<string, List<Vector3>> playerRouteCurrent = new Dictionary<string, List<Vector3>>();

    public static int spawnIndexBeginner = 0;
    public static int spawnIndexIntermediate = 0;

    public const int SKILL_BEGINNER = 0;
    public const int SKILL_INTERMEDIATE = 300;

    public override bool NeedVehicleToStart => false;

    private readonly Dictionary<Vector3, float> BEGINNER_SPAWNS = new Dictionary<Vector3, float>
    {
      { new Vector3(1683.6611, 3267.7104, 41.625206), -162},
      { new Vector3(1696.7466, 3271.403, 41.385006), -161},
      { new Vector3(1722.8834, 3278.6873, 41.194054), -160},
      { new Vector3(1723.9468, 3233.8052, 41.563965), 17},
      { new Vector3(1736.5269, 3236.5996, 41.563965), 17},
      { new Vector3(1750.1774, 3240.3157, 41.563965), 17},
    };

    private readonly Dictionary<Vector3, float> INTERMEDIATE_SPAWNS = new Dictionary<Vector3, float>()
    {
      { new Vector3(-1650.7899, -3178.5798, 15), 60},
      { new Vector3(-1643.098, -3165.7114, 15), 60},
      { new Vector3(-1635.0903, -3152.7354, 15), 60},
      { new Vector3(-1627.0435, -3138.8354, 15), 60},
      { new Vector3(-1517-0101, -3125-2798, 15), -118},
      { new Vector3(-1670.9293, -3116.0898, 15), -118},
    };

    //124 0 Velum

    private readonly Dictionary<int, List<Vector3>> ROUTE_BEGINNER = new Dictionary<int, List<Vector3>>//Bus_Skill_1_Route_1
    {
      { 0,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
           new Vector3(1645.9910888671875, 3236.744873046875, 40.98052978515625),
           new Vector3(302.6805114746094, 2867.93896484375, 204.81182861328125),
           new Vector3(-1093.6722412109375, 2737.1376953125, 257.575439453125),
           new Vector3(-2286.014892578125, 3019.12841796875, 33.4510498046875),
           new Vector3(-2471.854248046875, 3271.08935546875, 33.47834777832031),
           new Vector3(-623.9515380859375, 5313.12158203125, 181.6047821044922),
           new Vector3(1896.899658203125, 4824.203125, 208.77737426757812),
           new Vector3(2281.790283203125, 3606.98681640625, 132.3915252685547),
           new Vector3(1610.4461669921875, 3225.36376953125, 41.05073928833008),
        }
      },
      { 1,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
           new Vector3(1593.927490234375, 3193.30908203125, 41.170997619628906),
           new Vector3(961.5843505859375, 2278.5966796875, 251.17218017578125),
           new Vector3(924.3920288085938, 93.95357513427734, 282.3033142089844),
           new Vector3(963.6002197265625, -3101.551513671875, 177.8121337890625),
           new Vector3(-1265.1163330078125, -2990.142578125, 14.595105171203613),
           new Vector3(-1260.78662109375, -2806.293212890625, 14.587812423706055),
           new Vector3(-894.3707885742188, 82.7993392944336, 385.011962890625),
           new Vector3(919.4126586914062, 2553.385986328125, 135.39154052734375),
           new Vector3(1592.840087890625, 3192.8017578125, 41.169837951660156),
        }
      },
    };

    private readonly Dictionary<int, List<Vector3>> ROUTE_INTERMEDIATE = new Dictionary<int, List<Vector3>>
    {
      { 0,
        new List<Vector3>()
        {
          new Vector3(-1534.98828125, -3028.916748046875, 14.451109886169434),
          new Vector3(-1182.960205078125, -3236.542724609375, 67.93492126464844),
          new Vector3(942.8041381835938, -2997.95751953125, 323.1705322265625),
          new Vector3(2459.114501953125, -525.8928833007812, 409.09002685546875),
          new Vector3(2764.611572265625, 1482.853271484375, 457.73944091796875),
          new Vector3(3485.380615234375, 3652.9619140625, 343.3283996582031),
          new Vector3(2652.611572265625, 4737.7958984375, 206.23399353027344),
          new Vector3(2043.8521728515625, 4769.595703125, 42.007118225097656),
          new Vector3(2134.332763671875, 4781.857421875, 41.900352478027344),
          new Vector3(1943.1544189453125, 4721.03125, 57.76427459716797),
          new Vector3(1749.4105224609375, 3790.8955078125, 194.40440368652344),
          new Vector3(1203.5526123046875, 2707.182373046875, 342.80145263671875),
          new Vector3(-377.686279296875, 1256.92578125, 532.7467651367188),
          new Vector3(-820.6907958984375, -412.96466064453125, 311.0726013183594),
          new Vector3(-1073.534912109375, -1704.798583984375, 94.05522155761719),
          new Vector3(-1686.30126953125, -2815.478759765625, 14.87234115600586),
          new Vector3(-1617.498291015625, -2982.41259765625, 14.883989334106445),
        }
      },
      { 1,
        new List<Vector3>()
        {
          new Vector3(-1463.965576171875, -2875.571533203125, 14.882678031921387),
          new Vector3(-981.0889282226562, -3122.533203125, 56.10537338256836),
          new Vector3(-341.6023254394531, -2016.779541015625, 262.1709899902344),
          new Vector3(-1446.6815185546875, -894.4887084960938, 321.3404846191406),
          new Vector3(-3151.909912109375, 979.1404418945312, 335.3139953613281),
          new Vector3(-1309.160888671875, 4903.9140625, 388.6031494140625),
          new Vector3(31.35175895690918, 3690.413330078125, 333.4454345703125),
          new Vector3(-948.346923828125, 2766.284912109375, 239.0842742919922),
          new Vector3(-2312.5068359375, 3033.903076171875, 33.7471923828125),
          new Vector3(-2132.787109375, 3265.840087890625, 33.74031448364258),
          new Vector3(-2331.76611328125, 3148.581298828125, 33.7597541809082),
          new Vector3(-2564.848876953125, 2369.27783203125, 182.68736267089844),
          new Vector3(-1833.041259765625, 832.1589965820312, 398.28863525390625),
          new Vector3(-878.19384765625, -904.84521484375, 284.2839050292969),
          new Vector3(-1124.624755859375, -1821.9208984375, 74.77794647216797),
          new Vector3(-1631.8602294921875, -2720.09814453125, 14.873514175415039),
          new Vector3(-1543.793701171875, -2829.399169921875, 14.899491310119629),
        }
      },
    };

    public PilotJob()
    {
      JobStop += _JobStop;
    }

    private void _JobStop(Player player)
    {
      if (!playerVehiclePair.ContainsKey(player))
        return;

      CheckPointHandle.DeleteCheckpoints(player);

      playerVehiclePair[player].Delete();
      playerVehiclePair.Remove(player);
    }

    public string getSkill(int skillPoints)
    {
      if (skillPoints == SKILL_BEGINNER)
        return BEGINNER;
      else if (skillPoints == SKILL_INTERMEDIATE)
        return INTERMEDIATE;

      return "none";
    }

    private uint getPlayerJobVehicle(string type)
    {
      if (type == BEGINNER)
        return VEHICLE_BEGINNER;
      else if (type == INTERMEDIATE)
        return VEHICLE_INTERMEDIATE;
      else if (type == PROFESSIONAL)
        return VEHICLE_PROFESSIONAL;

      return 0;
    }

    [RemoteEvent("startPilotRoute")]
    public void StartPilotRoute(Player player, int skillPoints)
    {
      string type = getSkill(skillPoints);

      List<Vector3> selectedRoute = new List<Vector3>();
      Random random = new Random();
      Vector3 spawnPoint = null;
      float heading = 0;

      if (type == BEGINNER)
      {
        spawnPoint = BEGINNER_SPAWNS.Keys.ToList()[spawnIndexBeginner++ % BEGINNER_SPAWNS.Count];
        heading = BEGINNER_SPAWNS[spawnPoint];
        selectedRoute = ROUTE_BEGINNER.GetValueOrDefault(random.Next(0, ROUTE_BEGINNER.Count));
      }
      else if (type == INTERMEDIATE)
      {
        spawnPoint = INTERMEDIATE_SPAWNS.Keys.ToList()[spawnIndexIntermediate++ % INTERMEDIATE_SPAWNS.Count];
        heading = INTERMEDIATE_SPAWNS[spawnPoint];
        selectedRoute = ROUTE_INTERMEDIATE.GetValueOrDefault(random.Next(0, ROUTE_INTERMEDIATE.Count));
      }

      if (selectedRoute is null || selectedRoute.Count is 0)
      {
        Console.WriteLine($"[ERROR:BUSJOB] Player {player.Name} has empty route Vector3 List.");
        return;
      }
      if (spawnPoint is null)
      {
        Console.WriteLine($"[ERROR:BUSJOB] Player {player.Name} has empty spawn point.");
        return;
      }

      Vehicle vehicle = NAPI.Vehicle.CreateVehicle(getPlayerJobVehicle(type), spawnPoint, heading, 124, 0, "JOB");
      vehicle.NumberPlate = "JOB-" + vehicle.Id;

      if (vehicle is null)
      {
        Console.WriteLine($"[ERROR:BUSJOB] Player {player.Name} got no Vehicle set.");
        return;
      }

      if (!playerRouteCurrent.ContainsKey(player.Name))
        playerRouteCurrent.Add(player.Name, new List<Vector3>());

      playerRouteCurrent[player.Name] = selectedRoute;
      _CHANGING_VEHICLE.Add(player);
      if (playerVehiclePair.ContainsKey(player))
      {
        Vehicle previousVehicle = null;
        if (playerVehiclePair[player] != null)
          previousVehicle = playerVehiclePair[player];
        playerVehiclePair.Remove(player);

        previousVehicle?.Delete();
      }
      playerVehiclePair.Add(player, vehicle);
      player.SetIntoVehicle(vehicle.Handle, 0);
      CheckPointHandle.StartCheckPointRoute(player, selectedRoute, 0, CHECKPOINT_MARKER_ID, 40, 10, true, "PILOT:InCheckpoint"); //6, 23, 25, 26, 27, 28
    }

    public string getPlayerRouteType(Player player)
    {
      if (!playerRouteCurrent.ContainsKey(player.Name))
        return "none";

      List<Vector3> selectedRoute = playerRouteCurrent[player.Name];

      if (ROUTE_BEGINNER.Values.Where(v => v.VectorEquals(selectedRoute)).Count() != 0)
        return BEGINNER;
      else if (ROUTE_INTERMEDIATE.Values.Where(v => v.VectorEquals(selectedRoute)).Count() != 0)
        return INTERMEDIATE;

      return "none";
    }

    public int getSkillFromType(string type)
    {
      if (type == BEGINNER)
        return SKILL_BEGINNER;
      else if (type == INTERMEDIATE)
        return SKILL_INTERMEDIATE;

      return -1;
    }

    public override void LastCheckpoint(Player player)
    {
      string type = getPlayerRouteType(player);
      int skill = getSkillFromType(type);
      if (skill == -1)
      {
        StopJob(player, true);
        return;
      }

      playerRouteCurrent.Remove(player.Name);

      StartPilotRoute(player, skill);
    }

    public override void StartJobEndTimer(Player player)
    {
      if (!playerVehiclePair.ContainsKey(player) && _CHANGING_VEHICLE.Contains(player))
      {
        _CHANGING_VEHICLE.Remove(player);
        return;
      }

      if (JobManager.playerTimersJobVehicleRespawn.ContainsKey(player))
      {
        JobManager.playerTimersJobVehicleRespawn[player].Stop();
      }
      PlayerTimer playerTimer = new PlayerTimer(player, playerVehiclePair[player], 30000);
      playerTimer.Elapsed += JobTimerElapsed;

      if (!JobManager.playerTimersJobVehicleRespawn.ContainsKey(player))
        JobManager.playerTimersJobVehicleRespawn.Add(player, playerTimer);
      else
        JobManager.playerTimersJobVehicleRespawn[player] = playerTimer;

      player.SendChatMessage("~y~[JOB] ~w~Du hast das Fahrzeug verlassen,");
      player.SendChatMessage("~y~[JOB] ~w~Bist du nicht in 30 Sekunden zurück, ~r~wird der Job beendet!");
    }

    private void JobTimerElapsed(Player player, dynamic vehicle)
    {
      NAPI.Task.Run(() =>
      {
        StopJob(player, !player.GetData<bool>("isDead"));
        JobManager.playerTimersJobVehicleRespawn[player].Stop();
        JobManager.playerTimersJobVehicleRespawn.Remove(player);
      });
    }

    public override bool CheckVehicle(Player player, Vehicle vehicle)
    {
      if (!playerVehiclePair.ContainsKey(player))
        return false;

      if (playerVehiclePair[player] == vehicle)
        return true;

      return false;
    }
  }

  public class PilotJobEvents : Script
  {
    [RemoteEvent("PILOT:InCheckpoint")]
    public void PilotInCheckpoint(Player player)
    {
      if (!PilotJob.playerVehiclePair.ContainsKey(player) || !PilotJob.playerRouteCurrent.ContainsKey(player.Name))
        return;

      if (PilotJob.playerVehiclePair[player].Model is PilotJob.VEHICLE_BEGINNER)
        payWage(player, PilotJob.WAGE_BEGINNER / PilotJob.playerRouteCurrent[player.Name].Count);
      else if (PilotJob.playerVehiclePair[player].Model is PilotJob.VEHICLE_INTERMEDIATE)
        payWage(player, PilotJob.WAGE_INTERMEDIATE / PilotJob.playerRouteCurrent[player.Name].Count);
    }

    public void payWage(Player player, int wage)
    {
      using var dbContext = new DatabaseContext();
      User user = player.GetUser(dbContext);

      if (player.VehicleSeat == 0)
      {
        user.Wage += wage;
        user.PilotSkill++;
        if (user.PilotSkill == BusDriverJob.SKILL_INTERMEDIATE)
        {
          player.SendChatMessage($"~y~[JOB] ~w~Du hast nun die Route ~g~{BusDriverJob.INTERMEDIATE} ~w~freigeschaltet!");
          player.SendChatMessage($"~y~[JOB] ~w~Du kannst jetzt auch mit dem Velum fliegen!");
        }

        dbContext.SaveChanges();
      }
    }
  }
}
