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

namespace ReallifeGamemode.Server.Job
{
  public class BusDriverJob : JobBase
  {
    public override int Id => 4;

    public override string Name => "Busfahrer";

    public static Dictionary<string, List<Vector3>> playerRoutePair1 = new Dictionary<string, List<Vector3>>(); //skill 1
    public static Dictionary<string, List<Vector3>> playerRoutePair2 = new Dictionary<string, List<Vector3>>(); //skill 2
    public static Dictionary<string, List<Vector3>> playerRoutePair3 = new Dictionary<string, List<Vector3>>(); //skill 3

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

    public const int MARKER_DELAY = 4000;
    public const int MARKER_ID = 1;
    public const int MARKER_SIZE = 7;
    public const int MARKER_DIST = 6;
    public const string MARKER_EVENT = "BUSJOB:BusInCheckpoint";

    public const uint VEHICLE_BEGINNER = (uint)VehicleHash.Bus;
    public const uint VEHICLE_INTERMEDIATE = (uint)VehicleHash.Coach;
    public const uint VEHICLE_PROFESSIONAL = (uint)VehicleHash.Tourbus;

    public const int WAGE_BEGINNER = 400;
    public const int WAGE_INTERMEDIATE = 600;
    public const int WAGE_PROFESSIOAL = 650;

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

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

    //-623.76, -2083.1008, 5.9822865

    private static int spawnIndex = 0;

    private readonly List<Vector3> VEHICLE_SPAWNS = new List<Vector3>()
    {
      new Vector3(-555.02136, -2162.153, 5.988391),
      new Vector3(-568.4366, -2179.2156, 5.988391),
      new Vector3(-582.3364, -2194.5134, 5.988391),
      new Vector3(-598.5143, -2207.357, 5.988893),
    };

    private const float VEHICLE_HEADING = 50; //6.618084f;

    public override bool NeedVehicleToStart => false;

    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(-1018.1577758789062, -2732.403564453125, 10.658967971801758) ,
          new Vector3(-153.04013061523438, -2033.8385009765625, 19.712543487548828) ,
          new Vector3(50.42457580566406, -1536.9090576171875, 26.184476852416992) ,
          new Vector3(361.1451721191406, -1064.6044921875, 26.36113166809082) ,
          new Vector3(119.01465606689453, -785.609619140625, 28.267763137817383) ,
          new Vector3(-172.00689697265625, -815.9910888671875, 28.13607406616211) ,
          new Vector3(-707.7088623046875, -826.9969482421875, 20.451000213623047) ,
          new Vector3(-658.1038818359375, -1393.321533203125, 7.509778022766113) ,
          new Vector3(-1018.1826171875, -2732.371826171875, 10.656649589538574) ,
          new Vector3(-647.2696533203125, -2215.64501953125, 2.989798069000244)
        }
      },
      { 1,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(-567.6445922851562, -1233.4453125, 12.050300598144531),
          new Vector3(-509.224609375, -668.373291015625, 30.02402877807617),
          new Vector3(55.00559997558594, -749.8328247070312, 41.11421203613281),
          new Vector3(-173.65509033203125, -152.5533905029297, 40.615516662597656),
          new Vector3(-523.8310546875, -266.884033203125, 32.291507720947266),
          new Vector3(-1167.646728515625, -400.75, 32.39745330810547),
          new Vector3(-1408.329345703125, -567.8721923828125, 27.22767448425293),
          new Vector3(-1213.3565673828125, -1214.755859375, 4.5853986740112305),
          new Vector3(-746.8554077148438, -2372.227783203125, 11.740862846374512),
          new Vector3(-660.7366333007812, -2206.03662109375, 2.988998889923096),
        }
      },
      { 2,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(423.4793395996094, -2143.4169921875, 15.23659896850586),
          new Vector3(875.1618041992188, -1766.7913818359375, 26.780052185058594),
          new Vector3(1166.110107421875, -1422.72265625, 31.477935791015625),
          new Vector3(807.715087890625, -1356.7987060546875, 23.29298210144043),
          new Vector3(785.9387817382812, -780.5958251953125, 23.333005905151367),
          new Vector3(895.2793579101562, 55.24346923828125, 75.82550048828125),
          new Vector3(775.8052368164062, 596.2352905273438, 122.77734375),
          new Vector3(307.64422607421875, -762.0469360351562, 26.197702407836914),
          new Vector3(-105.66091918945312, -1683.9630126953125, 26.190542221069336),
          new Vector3(-644.0516967773438, -2218.673828125, 2.991928577423096),
        }
      },
      { 3,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(-694.1781616210938, -1199.3873291015625, 7.50633716583252),
          new Vector3(-1408.264892578125, -567.5278930664062, 27.21875),
          new Vector3(-1681.6112060546875, -503.3702392578125, 34.79117965698242),
          new Vector3(-1427.05712890625, -90.17198181152344, 49.015113830566406),
          new Vector3(-686.4015502929688, -374.3297424316406, 31.17094802856445),
          new Vector3(-509.60107421875, -668.41796875, 30.02873229980469),
          new Vector3(234.6927032470703, -857.5449829101562, 26.747934341430664),
          new Vector3(787.8258666992188, -1364.9345703125, 23.424083709716797),
          new Vector3(825.1477661132812, -1634.5733642578125, 27.521774291992188),
          new Vector3(-105.38816833496094, -1683.646728515625, 26.19083023071289),
          new Vector3(-655.6530151367188, -2209.579345703125, 2.98785924911499),
        }
      },
    };

    private readonly Dictionary<int, List<Vector3>> ROUTE_INTERMEDIATE = new Dictionary<int, List<Vector3>>
    {
      { 0,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(-1042.6405029296875, -2718.244384765625, 9.493847846984863),
          new Vector3(832.205322265625, -11.559977531433105, 76.72754669189453),
          new Vector3(2563.96826171875, 2633.976806640625, 35.279945373535156),
          new Vector3(1684.845947265625, 6402.1533203125, 28.877294540405273),
          new Vector3(-170.82965087890625, 6374.9560546875, 28.695466995239258),
          new Vector3(-1524.5302734375, 4998.1220703125, 60.54846954345703),
          new Vector3(-3234.168701171875, 974.0481567382812, 10.890801429748535),
          new Vector3(-1331.8995361328125, -1052.2794189453125, 5.4408793449401855),
          new Vector3(-647.2696533203125, -2215.64501953125, 2.989798069000244),
        }
      },
      { 1,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(1925.767333984375, 2614.566162109375, 46.16560363769531),
          new Vector3(299.0667419433594, 2642.93798828125, 44.60177993774414),
          new Vector3(1162.4556884765625, 1806.3663330078125, 74.3133773803711),
          new Vector3(1297.0450439453125, 1105.742919921875, 105.6315689086914),
          new Vector3(-524.4381103515625, -268.2084045410156, 35.28974533081055),
          new Vector3(427.09521484375, -960.2006225585938, 29.13089942932129),
          new Vector3(-567.5792846679688, -2212.6533203125, 5.859220504760742),
        }
      },
      { 2,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(-1855.54,153.604,79.0297),
          new Vector3(-1538.72,1375.19,124.3),
          new Vector3(-1101.74,2668.48,17.7363),
          new Vector3(1964.14,3718.04,31.2255),
          new Vector3(2566.1,396.879,107.463),
          new Vector3(254.405,-982.937,28.274),
          new Vector3(-562.68, -2203.85, 4.5),
        }
      },
      { 3,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(-1037.8,-2716.02,12.7963),
          new Vector3(1662.69,4849.72,40.9165),
          new Vector3(57.8575,3735.46,38.7301),
          new Vector3(-1109.48,2681,17.8602),
          new Vector3(-2536.35,2322.65,32.0599),
          new Vector3(-3232.01,961.997,12.1515),
          new Vector3(-3014.22,364.543,13.7242),
          new Vector3(-1580.52,-652.24,28.5874),
          new Vector3(-578.954,-2224.8,4.75774),
        }
      },
    };

    private readonly Dictionary<int, List<Vector3>> ROUTE_PROFESSIONAL = new Dictionary<int, List<Vector3>>
    {
      { 0,
        new List<Vector3>()
        {
          new Vector3(-146.62071, -2178.8228, 10.194298),
          new Vector3(14.580393, -1578.6385, 29.212185),
          new Vector3(222.91612, -1098.8556, 29.227453),
          new Vector3(246.44946, -648.45496, 39.420746),
          new Vector3(102.181, -298.95276, 46.04399),
          new Vector3(-104.91002, -606.26013, 36.06103),
          new Vector3(-288.1007, -1204.5107, 24.403156),
          new Vector3(-166.23526, -1574.4166, 35.152023),
          new Vector3(-60.337997, -1976.121, 16.486664),
          new Vector3(-599.1891, -2049.2695, 6.14637),
        }
      },
      { 1,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          //new Vector3(-597.8766479492188, -2053.534423828125, 5.853154182434082),
          new Vector3(-895.4871826171875, -2074.380126953125, 8.602267265319824),
          new Vector3(-667.8001708984375, -1233.9366455078125, 10.274462699890137),
          new Vector3(-1349.004150390625, -1119.2432861328125, 4.00660514831543),
          new Vector3(-2127.448974609375, -333.7845153808594, 13.013818740844727),
          new Vector3(-1426.419189453125, -90.23416137695312, 51.81801223754883),
          new Vector3(-827.4555053710938, -235.72817993164062, 36.84095764160156),
          new Vector3(-558.2310791015625, -161.801513671875, 37.93125534057617),
          new Vector3(220.4048309326172, -852.0598754882812, 29.874643325805664),
          new Vector3(363.25042724609375, -1470.600830078125, 28.91864776611328),
          new Vector3(-200.07644653320312, -1941.02783203125, 27.382631301879883),
          new Vector3(-605.2278442382812, -2087.974853515625, 5.752280235290527),
        }
      },
      { 2,
        new List<Vector3>()
        {
          //new Vector3(-601.733, -2049.285, 6.090),
          new Vector3(-599.541, -2054.42, 6.0372),
          new Vector3(-666.861, -1241.26, 10.5494),
          new Vector3(-1396.98, -773.447, 20.68),
          new Vector3(-1205.3, -130.106, 40.9405),
          new Vector3(-506.147, -282.95, 35.4909),
          new Vector3(244.279, -860.634, 29.5133),
          new Vector3(1021.58, -725.525, 57.6664),
          new Vector3(769.912, -1983.54, 29.2573),
          new Vector3(-566.381, -2209.74, 5.88064),
        }
      },
    };

    public BusDriverJob()
    {
      JobStart += BusDriverJob_JobStart;
      JobStop += _JobStop;
    }

    private void BusDriverJob_JobStart(Player player)
    {
      User user = player.GetUser();
      player.TriggerEvent("SERVER:StartBusJob", user.BusSkill);
    }

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

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

    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;
      else if (ROUTE_PROFESSIONAL.Values.Where(v => v.VectorEquals(selectedRoute)).Count() != 0)
        return PROFESSIONAL;

      return "none";
    }

    public int getPlayerRouteInex(Player player)
    {
      if (!playerRouteCurrent.ContainsKey(player.Name))
        return -1;

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

      for (int i = 0; i < 100; i++)
      {
        if (!ROUTE_BEGINNER.ContainsKey(i) && !ROUTE_INTERMEDIATE.ContainsKey(i) && !ROUTE_PROFESSIONAL.ContainsKey(i))
          break;

        if (ROUTE_BEGINNER.ContainsKey(i))
        {
          if (ROUTE_BEGINNER[i].VectorEquals(selectedRoute))
            return i;
        }
        if (ROUTE_INTERMEDIATE.ContainsKey(i))
        {
          if (ROUTE_INTERMEDIATE[i].VectorEquals(selectedRoute))
            return i;
        }
        if (ROUTE_PROFESSIONAL.ContainsKey(i))
        {
          if (ROUTE_PROFESSIONAL[i].VectorEquals(selectedRoute))
            return i;
        }
      }

      return -1;
    }

    private uint getPlayerJobVehicle(Player player)
    {
      string type = getPlayerRouteType(player);

      if (type == BEGINNER)
        return VEHICLE_BEGINNER;
      else if (type == INTERMEDIATE)
        return VEHICLE_INTERMEDIATE;
      else if (type == PROFESSIONAL)
        return VEHICLE_PROFESSIONAL;

      return 0;
    }

    [RemoteEvent("CLIENT:StartBusRoute")]
    public void StartBusRoute(Player player, string type)
    {
      User user = player.GetUser();
      if (type == INTERMEDIATE && user.BusSkill < SKILL_INTERMEDIATE) { player.TriggerEvent("MenuSelect:Error"); return; }
      if (type == PROFESSIONAL && user.BusSkill < SKILL_PROFESSIONAL) { player.TriggerEvent("MenuSelect:Error"); return; }

      List<Vector3> selectedRoute = new List<Vector3>();
      int index;
      if (playerRouteCurrent.ContainsKey(player.Name))
      {
        index = getPlayerRouteInex(player);
      }
      else
      {
        Random random = new Random();
        index = random.Next(0, 7);
      }

      if (type == BEGINNER)
      {
        index %= ROUTE_BEGINNER.Count;
        if (playerRoutePair1.ContainsKey(player.Name))
        {
          selectedRoute = playerRoutePair1[player.Name];
        }
        else
        {
          selectedRoute = ROUTE_BEGINNER.GetValueOrDefault(index);
          playerRoutePair1.Add(player.Name, selectedRoute);
        }
      }
      else if (type == INTERMEDIATE)
      {
        index %= ROUTE_INTERMEDIATE.Count;

        if (playerRoutePair2.ContainsKey(player.Name))
        {
          selectedRoute = playerRoutePair2[player.Name];
        }
        else
        {
          selectedRoute = ROUTE_INTERMEDIATE.GetValueOrDefault(index);
          playerRoutePair2.Add(player.Name, selectedRoute);
        }
      }
      else if (type == PROFESSIONAL)
      {
        index %= ROUTE_PROFESSIONAL.Count;

        if (playerRoutePair3.ContainsKey(player.Name))
        {
          selectedRoute = playerRoutePair3[player.Name];
        }
        else
        {
          selectedRoute = ROUTE_PROFESSIONAL.GetValueOrDefault(index);
          playerRoutePair3.Add(player.Name, selectedRoute);
        }
      }

      if (playerRouteCurrent.ContainsKey(player.Name))
        playerRouteCurrent.Remove(player.Name);
      playerRouteCurrent.Add(player.Name, selectedRoute);

      if (selectedRoute is null || selectedRoute.Count is 0)
      {
        Console.WriteLine($"[ERROR:BUSJOB] Player {player.Name} has empty route Vector3 List -BUSDATA TYPE: {type}, INDEX {index}.");
        return;
      }

      Vector3 spawnPoint = VEHICLE_SPAWNS[spawnIndex++ % VEHICLE_SPAWNS.Count];
      Vehicle vehicle = NAPI.Vehicle.CreateVehicle(getPlayerJobVehicle(player), spawnPoint, VEHICLE_HEADING, 111, 111, "JOB");
      vehicle.NumberPlate = "JOB-" + vehicle.Id;

      if (vehicle is null)
      {
        Console.WriteLine($"[ERROR:BUSJOB] Player {player.Name} got no Vehicle set -BUSDATA TYPE: {type}, INDEX {index}.");
        return;
      }
      _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);

      player.TriggerEvent("CLIENT:PlaySound", "jobs/busfahrer/FahrplanAbfahrt", "wav", 15);
      player.StartCheckPointRoute(selectedRoute, MARKER_DELAY, MARKER_ID, MARKER_SIZE, MARKER_DIST, true, MARKER_EVENT);
      if (index != -1)
        player.SendChatMessage($"~y~[JOB] ~w~Dir wurde ~g~ Route {index + 1}~w~ zugeteilt.");
    }

    public override void LastCheckpoint(Player player)
    {
      Vehicle v = player.Vehicle;
      player.SendChatMessage("~y~[JOB] ~w~Die neue Route lädt. Bitte warten...");
      string type = getPlayerRouteType(player);

      if (type == BEGINNER)
        BusJobEvents.payWage(player, WAGE_BEGINNER);
      else if (type == INTERMEDIATE)
        BusJobEvents.payWage(player, WAGE_INTERMEDIATE);
      else if (type == PROFESSIONAL)
        BusJobEvents.payWage(player, WAGE_PROFESSIOAL);

      NAPI.Task.Run(() =>
      {
        if (type == BEGINNER)
          playerRoutePair1.Remove(player.Name);
        else if (type == INTERMEDIATE)
          playerRoutePair2.Remove(player.Name);
        else if (type == PROFESSIONAL)
          playerRoutePair3.Remove(player.Name);

        playerRouteCurrent.Remove(player.Name);
        if (!GetPlayerInJob().Contains(player))
          return;

        BusDriverJob job = JobManager.GetJob<BusDriverJob>();
        StartBusRoute(player, type);
      }, delayTime: 10000);

      if (!player.IsInVehicle || player.VehicleSeat != 0) return;
      Vehicle veh = player.Vehicle;
      if (!(veh.GetData<IndicatorData>("indicatorData") is IndicatorData data)) data = new IndicatorData();
      data.Left = false;
      data.Right = false;
      veh.SetData("indicatorData", data);
      NAPI.ClientEvent.TriggerClientEventForAll("SERVER:setIndicatorStatus", veh.Handle.Value, data.Left, data.Right);
    }

    public void BusCheckpoint(Player player)
    {
      if (!player.IsInVehicle || player.VehicleSeat != 0) return;
      Vehicle veh = player.Vehicle;
      if ((VehicleHash)veh.Model == VehicleHash.Bus)
      {
        player.TriggerEvent("CLIENT:PlaySound", "jobs/busfahrer/AbfahrtHaltestelleBus", "wav", 25);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 0, false, 1850);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 1, false, 1850);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 2, false, 1850);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 3, false, 1850);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 0, false, 1850);
        NAPI.Task.Run(() =>
        {
          player.TriggerEvent("CLIENT:UnFreezeVehicle", veh);
        }, delayTime: 1850);
      }
      if ((VehicleHash)veh.Model == VehicleHash.Coach)
      {
        player.TriggerEvent("CLIENT:PlaySound", "jobs/busfahrer/AbfahrtHaltestelleCoach", "wav", 35);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 0, false, 1000);
        NAPI.Task.Run(() =>
        {
          player.TriggerEvent("CLIENT:UnFreezeVehicle", veh);
        }, delayTime: 1000);
      }
      if ((VehicleHash)veh.Model == VehicleHash.Tourbus)
      {
        player.TriggerEvent("CLIENT:PlaySound", "jobs/busfahrer/AbfahrtHaltestelleTourbus", "wav", 25);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 3, false, 2600);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 2, false, 2600);
        player.TriggerEvent("CLIENT:SetDoorShutDelayed", 3, false, 2600);
        NAPI.Task.Run(() =>
        {
          player.TriggerEvent("CLIENT:UnFreezeVehicle", veh);
        }, delayTime: 2600);
      }
      //user.TriggerEvent("CLIENT:UnFreezeVehicle", veh);
    }

    public void AtBusStop(Player player)
    {
      if (!player.IsInVehicle || player.VehicleSeat != 0) return;
      Vehicle veh = player.Vehicle;
      player.TriggerEvent("CLIENT:FreezeVehicle", veh);
      player.TriggerEvent("CLIENT:UnFreezeVehicle", veh);
      player.TriggerEvent("CLIENT:PlaySound", "jobs/busfahrer/AnfahrtHaltestelle", "wav", 50);
      if ((VehicleHash)veh.Model == VehicleHash.Bus)
      {
        player.TriggerEvent("CLIENT:SetDoorOpen", 0, false, false);
        player.TriggerEvent("CLIENT:SetDoorOpen", 1, false, false);
        player.TriggerEvent("CLIENT:SetDoorOpen", 2, false, false);
        player.TriggerEvent("CLIENT:SetDoorOpen", 3, false, false);
        player.TriggerEvent("CLIENT:SetDoorOpen", 0, false, false);
        NAPI.Task.Run(() =>
        {
          BusCheckpoint(player);
        }, delayTime: 3600);
      }
      if ((VehicleHash)veh.Model == VehicleHash.Coach)
      {
        player.TriggerEvent("CLIENT:SetDoorOpen", 0, false, false);
        NAPI.Task.Run(() =>
        {
          BusCheckpoint(player);
        }, delayTime: 2800);
      }
      if ((VehicleHash)veh.Model == VehicleHash.Tourbus)
      {
        player.TriggerEvent("CLIENT:SetDoorOpen", 2, false, false);
        player.TriggerEvent("CLIENT:SetDoorOpen", 3, false, false);
        NAPI.Task.Run(() =>
        {
          BusCheckpoint(player);
        }, delayTime: 3250);
      }
      if (!(veh.GetData<IndicatorData>("indicatorData") is IndicatorData data)) data = new IndicatorData();
      data.Left = false;
      data.Right = true;
      veh.SetData("indicatorData", data);
      NAPI.ClientEvent.TriggerClientEventForAll("SERVER:setIndicatorStatus", veh.Handle.Value, data.Left, data.Right);

      NAPI.Task.Run(() =>
      {
        veh.Position = new Vector3(veh.Position.X, veh.Position.Y, veh.Position.Z + 0.1);

        player.TriggerEvent("CLIENT:FreezeVehicle", veh);
      }, delayTime: 500);
    }

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

      if (!playerVehiclePair.ContainsKey(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 BusJobEvents : Script
  {
    [RemoteEvent("BUSJOB:BusInCheckpoint")]
    public void BusInCheckpoint(Player player)
    {
      if (!BusDriverJob.playerVehiclePair.ContainsKey(player) || !BusDriverJob.playerRouteCurrent.ContainsKey(player.Name))
        return;

      if (BusDriverJob.playerVehiclePair[player].Model is BusDriverJob.VEHICLE_BEGINNER)
      {
        payWage(player, BusDriverJob.WAGE_BEGINNER / BusDriverJob.playerRouteCurrent[player.Name].Count);
      }
      else if (BusDriverJob.playerVehiclePair[player].Model is BusDriverJob.VEHICLE_INTERMEDIATE)
      {
        payWage(player, BusDriverJob.WAGE_INTERMEDIATE / BusDriverJob.playerRouteCurrent[player.Name].Count);
        payWage(player, 0);
      }
      else if (BusDriverJob.playerVehiclePair[player].Model is BusDriverJob.VEHICLE_PROFESSIONAL)
      {
        payWage(player, BusDriverJob.WAGE_PROFESSIOAL / BusDriverJob.playerRouteCurrent[player.Name].Count);
      }
    }

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

      if (player.VehicleSeat == 0)
      {
        user.Wage += wage;
        user.BusSkill++;
        if (user.BusSkill == 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 Coach fahren!");
        }
        if (user.BusSkill == BusDriverJob.SKILL_PROFESSIONAL)
        {
          player.SendChatMessage($"~y~[JOB] ~w~Du hast nun die Route ~g~{BusDriverJob.PROFESSIONAL} ~w~freigeschaltet!");
          player.SendChatMessage($"~y~[JOB] ~w~Du kannst jetzt auch mit dem Tourbus fahren!");
        }

        dbContext.SaveChanges();
      }
    }
  }
}
