using System.Collections.Generic;
using GTANetworkAPI;
using Newtonsoft.Json;
using ReallifeGamemode.Server.Services;
using System.Linq;
using ReallifeGamemode.Services;
using ReallifeGamemode.Database.Entities;
using ReallifeGamemode.Database.Models;
using Microsoft.EntityFrameworkCore;
using System;

/**
 * @overview Life of German Reallife - Server Factions Medic Medic.cs
 * @author VegaZ
 * @copyright (c) 2008 - 2018 Life of German
 */

namespace ReallifeGamemode.Server.Factions.Medic
{
  public class Medic : Script
  {
    public static List<MedicTask> ReviveTasks = new List<MedicTask>();
    public static List<MedicTask> HealTasks = new List<MedicTask>();
    public static List<MedicTask> FireTasks = new List<MedicTask>();
    public static int ReviveIncome = 100;
    public static int dutyMedics = 0;
    public static int reviveTaskTime = 240;

    public static void AddTaskToList(MedicTask task)
    {
      if (task == null)
      {
        return;
      }

      switch (task.Type)
      {
        case MedicTaskType.REVIVE:
          ReviveTasks.Add(task);
          break;

        case MedicTaskType.HEAL:
          HealTasks.Add(task);
          break;

        case MedicTaskType.FIRE:
          FireTasks.Add(task);
          break;
      }
    }

    public static void RemoveTaskFromList(MedicTask task)
    {
      if (task == null)
      {
        return;
      }

      switch (task.Type)
      {
        case MedicTaskType.REVIVE:
          ReviveTasks.Remove(task);
          break;

        case MedicTaskType.HEAL:
          HealTasks.Remove(task);
          break;

        case MedicTaskType.FIRE:
          FireTasks.Remove(task);
          break;
      }
    }

    public static void UpdateTaskTimeLeft()
    {
      DateTime actualTime = DateTime.Now;
      if (ReviveTasks.Count != 0)
      {
        foreach (var task in ReviveTasks)
        {
          if (task.MedicName != null)
          {
            var taskTimeLeft = Math.Abs((Int32)(((DateTimeOffset)actualTime).ToUnixTimeSeconds() - ((DateTimeOffset)task.Time).ToUnixTimeSeconds() - reviveTaskTime));
            task.TimeLeft = taskTimeLeft;
            var medic = PlayerService.GetPlayerByNameOrId(task.MedicName);
            if(task.MedicName != "none") medic.TriggerEvent("setTaskTimeLeft", taskTimeLeft);
          }
        }
      }
    }

    [RemoteEvent("loadMedicTasks")]
    public void LoadMedicTasks(Player player, int type)
    {
      switch (type)
      {
        case 0:
          player.TriggerEvent("showMedicTasks", 0, JsonConvert.SerializeObject(ReviveTasks));
          break;

        case 1:
          player.TriggerEvent("showMedicTasks", 1, JsonConvert.SerializeObject(HealTasks));
          break;

        case 2:
          player.TriggerEvent("showMedicTasks", 2, JsonConvert.SerializeObject(FireTasks));
          break;
      }
    }

    [RemoteEvent("updateMedicTask")]
    public void UpdateMedicTasks(Player player, int type, int index)
    {
      Player target = PlayerService.GetPlayerByNameOrId(ReviveTasks[index].Victim);
      switch (type)
      {
        case 0:
          
          ReviveTasks[index].MedicName = player.Name;
          ChatService.BroadcastFaction("~y~[MEDIC] ~w~" + player.Name + " hat den Reviveauftrag von " + ReviveTasks[index].Victim + " angenommen.", new List<int>() { 2 });
          target.SendNotification("~w~Sanitäter~g~ " + player.Name + "~w~ eilt zur Rettung.");

          break;

        case 1:
          HealTasks[index].MedicName = player.Name;
          ChatService.BroadcastFaction("~y~[MEDIC] ~w~" + player.Name + " hat den Healauftrag von " + ReviveTasks[index].Victim + " angenommen.", new List<int>() { 2 });
          target.SendNotification("~w~Sanitäter~g~ " + player.Name + "~w~ hat deinen Auftrag angenommen.");
          break;

        case 2:
          FireTasks[index].MedicName = player.Name;
          break;
      }
    }

    [RemoteEvent("delHealTask")]
    public static void delHealTask(Player player)
    {
      MedicTask task = HealTasks.FirstOrDefault(t => t.Victim == player.Name);
      RemoveTaskFromList(task);
      player.SetData("healauftrag", false);
    }

    [RemoteEvent("delHealTaskAsMedic")]
    public static void delHealTaskAsMedic(Player player, string victimName)
    {
      MedicTask task = HealTasks.FirstOrDefault(t => t.Victim == victimName);
      RemoveTaskFromList(task);
      player.SetData("healauftrag", false);
    }

    [RemoteEvent("delReviveTask")]
    public static void delReviveTask(Player player)
    {
      MedicTask task = ReviveTasks.FirstOrDefault(t => t.Victim == player.Name);
      RemoveTaskFromList(task);
    }
    [RemoteEvent("delReviveTaskMedic")]
    public static void delReviveTaskMedic(Player player)
    {
      MedicTask task = ReviveTasks.FirstOrDefault(t => t.MedicName == player.Name);
      RemoveTaskFromList(task);
    }

    [RemoteEvent("CutMedicEarnings")]
    public void CutMedicEarnings(Player player)
    {
      MedicTask task = ReviveTasks.FirstOrDefault(t => t.Victim == player.Name);
      var medic = PlayerService.GetPlayerByNameOrId(task.MedicName);
      medic.TriggerEvent("cutMedicEarnings");
    }
    [RemoteEvent("PayCutMedicEarnings")]
    public void PayCutMedicEarnings(Player player)
    {
      using var dbContext = new DatabaseContext();
      {
        dbContext.Factions.Include(f => f.BankAccount).Where(f => f.Id == 2).First().BankAccount.Balance += Medic.ReviveIncome / 2;
        player.SendNotification($"Du hast den Einsatzort erreicht und ~g~{Medic.ReviveIncome / 2}$ ~s~für die Fraktion verdient.");
        Medic.delReviveTaskMedic(player);
        dbContext.SaveChanges();
      }
    }

    [RemoteEvent("MedicTaskTimeout")]
    public void RemoveMedicTask(Player player)
    {
      Medic.delReviveTaskMedic(player);
    }

    [RemoteEvent("getTaskTimeLeft")]
    public void GetTaskTimeLeft(Player player, string victimName)
    {
      using var dbContext = new DatabaseContext();
      {
        var activeTaskTime = ReviveTasks.FirstOrDefault(t => t.MedicName == player.Name && t.Victim == victimName).TimeLeft;

        player.TriggerEvent("setTaskTimeLeft", activeTaskTime);
      }
    }

    public static void UpdateDutyMedics(int modifier)
    {
      dutyMedics = dutyMedics + modifier;
      NAPI.ClientEvent.TriggerClientEventForAll("updateDutyMedics", dutyMedics);
    }
  }
}
