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

namespace ReallifeGamemode.Server.Job
{
  internal class TaxiDriverJob : JobBase
  {
    public List<TaxiContract> TaxiContracts { get; set; } = new List<TaxiContract>();

    private static readonly Dictionary<NetHandle, Vector3> lastPositions = new Dictionary<NetHandle, Vector3>();

    public override int Id => 1;

    public override string Name => "Taxifahrer";

    public override bool NeedVehicleToStart => true;

    public override bool Deactivated => true;

    private static TaxiDriverJob _Instance;

    public TaxiDriverJob()
    {
      JobStart += TaxiDriverJobJobStart;
      JobStop += TaxiDriverJobJobStop;
    }

    public static TaxiDriverJob GetInstance()
    {
      if (_Instance == null)
        _Instance = new TaxiDriverJob();
      return _Instance;
    }

    private void TaxiDriverJobJobStart(Player player)
    {
      player.Vehicle.SetSharedData("vehicleTaxiLight", true);
      player.TriggerEvent("CLIENT:setFarePrice");
    }

    private void TaxiDriverJobJobStop(Player player)
    {
      if (!player.IsInVehicle)
        return;
      player.Vehicle.SetSharedData("vehicleTaxiLight", false);
      int Id = player.GetUser().Id;
      player.ResetData("DriverPrice");
      Vehicle v = player.Vehicle;

      foreach (Player occupant in v.Occupants)
      {
        occupant.TriggerEvent("CLIENT:cancelFare");
      }
    }

    [RemoteEvent("SERVER:failedFarePrice")]
    private void SrvEvent_failedFarePrice(Player player)
    {
      ChatService.ErrorMessage(player, "Bitte richtigen Wert eintragen");
      TaxiDriverJobJobStop(player);
    }

    [RemoteEvent("SERVER:setFare")]
    private void SrvEvent_setFare(Player player, int amount)
    {
      player.SetData<int>("DriverPrice", amount);
      player.TriggerEvent("CLIENT:startFare");
    }

    [RemoteEvent("SERVER:payFare")]
    private void SrvEvent_payFare(Player player, int amount, float km)
    {
      int id = player.GetUser().Id;
      player.SetData<float>("FareKm", km);
      int targetId = player.GetData<int>("Passager");
      if (targetId == 0) return;
     
      using (var dbContext = new DatabaseContext())
      {
        if (player.HasData("hasPassager"))
        {
          User target = dbContext.Users.Where(u => u.Id == targetId).FirstOrDefault();
            player.SendNotification("~r~[Info] ~w~ Dein Kunde hat kein Geld mehr auf der Hand.");
          
          if((target.Handmoney - amount) <= 0)
          {
            Player targetmoney = PlayerService.GetPlayerByNameOrId(Convert.ToString(targetId));
            targetmoney.SendNotification("~r~[Fehler] ~w~ Du hast kein Geld mehr auf der Hand.");
            player.SendNotification("~r~[Fehler] ~w~ Dein Fahrgast kann dich nicht mehr bezahlen.");
            player.TriggerEvent("CLIENT:cancelFare");
            targetmoney.TriggerEvent("CLIENT:cancelFareCustomer");
            targetmoney.WarpOutOfVehicle();
          }
          else 
          { 
            target.Handmoney -= amount;
            player.GetUser(dbContext).Wage += amount;
            dbContext.SaveChanges();
          }
          //target.Player.TriggerEvent("SERVER:SET_HANDMONEY", target.Handmoney);
        }
      }
    }

    /*
     public static void StartTaxiTimer()
     {
       Timer timer = new Timer(500);
       timer.Start();
       timer.Elapsed += UpdateFare;
     }
     */

    public static void UpdateFare()
    {
      foreach (var player in GetPlayerInJob())
      {
        User u = player.GetUser();
        if (u.JobId != 1) return;
        if (!player.HasData("hasPassager")) { player.SetData<bool>("hasPassager", false); continue; }
        int playerId = player.GetUser().Id;
        if (player.IsInVehicle)
        {
          Vehicle v = player.Vehicle;
          Vector3 lastPosition = v.Position;
          if (lastPositions.ContainsKey(v.Handle)) lastPosition = lastPositions[v.Handle];
          lastPositions[v.Handle] = v.Position;

          double distance = lastPosition.DistanceTo(v.Position) / 1000.0;

          if (player.GetUser()?.IsAdmin(AdminLevel.PLAYER) ?? true)
          {
            if (distance > 0.5) { ChatService.BroadcastAdmin($"Möglicher Cheater - {player.Name}", AdminLevel.MAPPING); continue; }
          }

          if (!player.GetData<bool>("hasPassager")) continue;
          foreach (Player occupant in v.Occupants)
          {
            occupant.TriggerEvent("CLIENT:updateFare", JsonConvert.SerializeObject(distance));
          }
        }
      }
    }
  }
}
