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

namespace ReallifeGamemode.Server.Gangwar
{
  public class Turf
  {

    public int TurfID { get; set; }
    public string TurfName { get; set; }
    public int Color { get; set; }
    public string Owner { get; set; }
    public string Attacker { get; set; }
    public int Att_Score { get; set; }
    public int Def_Score { get; set; }
    public string status { get; set; }
    public List<Player> playerInside { get; set; }
    public Timer timer { get; set; }
    public Player[] playerInGangwar { get; set; }
    public int timerCount;


    public Turf(int TurfID, string TurfName, int color, string Owner)
    {
      this.TurfID = TurfID;
      this.TurfName = TurfName;
      this.Color = color;
      this.Owner = Owner;
      this.Attacker = null;
      this.Att_Score = 50;
      this.Def_Score = 50;
      this.status = "normal";
      this.timer = null;
      this.playerInside = new List<Player>();
      this.timerCount = 0;
    }

    public int getId()
    {
      return this.TurfID;
    }

    public string getName()
    {
      return this.TurfName;
    }

    public int getColor()
    {
      return this.Color;
    }

    public string getOwner()
    {
      return this.Owner;
    }

    public string getAttacker()
    {
      return this.Attacker;
    }

    private void TurfTick()
    {
      this.timer = new System.Timers.Timer(1000);

      this.timer.Elapsed += Tick;
      this.timer.AutoReset = true;
      this.timer.Enabled = true;
      this.timerCount = 0;
    }

    private void Tick(object sender, System.Timers.ElapsedEventArgs e)
    {
      if (this.status == "attack")
      {
        update();
      }
    }



    private void update()
    {
      #region Ticket system
      /*
      try
      {
        Player[] owners = NAPI.Pools.GetAllPlayers().Where(c => c.GetUser().Faction.Name == this.Owner).ToArray();
        Player[] attackers = NAPI.Pools.GetAllPlayers().Where(c => c.GetUser().Faction.Name == this.Attacker).ToArray();
      }catch(NullReferenceException ex)
      {
        int i = 0;
        foreach(var c in playerInGangwar)
        {
          if (!NAPI.Entity.DoesEntityExist(c.Handle))
          {
            this.playerInside = this.playerInside.Where(gp => gp != c).ToArray();
          }
          i++;
        }
      }
        if (owners.Length > attackers.Length)
          this.Att_Score -= owners.Length - attackers.Length;
        if(owners.Length < attackers.Length)
          this.Def_Score -= attackers.Length - owners.Length;
        */
      #endregion
      foreach (Player gangwarPlayer in this.playerInGangwar)
      {
        gangwarPlayer.TriggerEvent("GangwarScore", this.Attacker, this.Owner, this.Att_Score, this.Def_Score);
      }
      if (this.Def_Score <= 0)
      {
        this.takeOver(this.Attacker);
      }
      else if (this.Att_Score <= 0)
      {
        this.takeOver(this.Owner);
      }
      timerCount += 1;
      if (timerCount >= 900) //change to 900 (seconds) before release for testing reasons change to whatever you like
      {
        if (this.Def_Score > this.Att_Score)
        {
          foreach (Player gangwarPlayer in this.playerInGangwar)
          {
            gangwarPlayer.TriggerEvent("GangwarScore", this.Attacker, this.Owner, 0, 0);
          }
          this.takeOver(this.Owner);
          this.Att_Score = 0;
        }
        else if (this.Def_Score < this.Att_Score)
        {
          foreach (Player gangwarPlayer in this.playerInGangwar)
          {
            gangwarPlayer.TriggerEvent("GangwarScore", this.Attacker, this.Owner, 0, 0);
          }
          this.takeOver(this.Attacker);
          this.Def_Score = 0;
          return;
        }
        else if (this.Def_Score == this.Att_Score)
        {
          foreach (Player gangwarPlayer in this.playerInGangwar)
          {
            gangwarPlayer.TriggerEvent("GangwarScore", this.Attacker, this.Owner, 0, 0);
          }
          this.takeOver(this.Attacker);
          this.Def_Score = 0;

          return;
        }
      }
    }

    public void enter(Player client)
    {
      if (this.status == "attack")
      {
        if (client.GetUser().Faction.Name != getOwner() && client.GetUser().Faction.Name != getAttacker())
          return;
        Player gPlayer = playerInGangwar.Where(c => c.GetUser().Id == client.GetUser().Id).FirstOrDefault();
        if (gPlayer == null)
        {
          using (var dbContext = new DatabaseContext())
          {
            ChatService.BroadcastFaction("~y~[GANGWAR] ~r~" + client.Name + "~w~ ist nicht im Gangwar beteiligt !", dbContext.Factions.Where(f => f.Name == getOwner()).FirstOrDefault());
            ChatService.BroadcastFaction("~y~[GANGWAR] ~r~" + client.Name + "~w~ ist nicht im Gangwar beteiligt !", dbContext.Factions.Where(f => f.Name == getAttacker()).FirstOrDefault());
          }
          return;
        }
      }

      if (playerInside.Find(c => c == client) == null)
      {
        playerInside.Add(client);
        client.SetData("GotInsideOfTurf", true);
      }
    }

    public void leave(Player client)
    {
      if (playerInside.Find(c => c == client) != null)
      {
        this.playerInside = this.playerInside.Where(c => c != client).ToList();
        if (this.status != "attack")
          client.ResetData("GotInsideOfTurf");
      }
    }

    public void takeOver(string FactionName)
    {
      this.timer.Stop();
      this.timer = null;
      using (var dbContext = new DatabaseContext())
      {
        if (getOwner() == FactionName)
        {
          Player[] owners = NAPI.Pools.GetAllPlayers().Where(c => c.IsLoggedIn() && c.GetUser().Faction.Name == this.Owner).ToArray();
          Player[] attackers = NAPI.Pools.GetAllPlayers().Where(c => c.IsLoggedIn() && c.GetUser().Faction.Name == this.Attacker).ToArray();
          foreach (var o in owners)
          {
            o.TriggerEvent("CLIENT:win");
          }
          foreach (var a in attackers)
          {
            a.TriggerEvent("CLIENT:loose");
          }
          ChatService.BroadcastFaction("~y~[GANGWAR] ~w~Deine Fraktion hat erfolgreich das Gebiet  ~g~" + getName() + "~w~ verteidigt.", dbContext.Factions.Where(f => f.Name == getOwner()).FirstOrDefault());
          ChatService.BroadcastFaction("~y~[GANGWAR] ~w~Deine Fraktion hat den Angrif auf das Gebiet ~r~" + getName() + "~w~ verloren.", dbContext.Factions.Where(f => f.Name == getAttacker()).FirstOrDefault());
        }
        else if (getOwner() != FactionName)
        {
          ChatService.BroadcastFaction("~y~[GANGWAR] ~w~Deine Fraktion konnte das Gebiet ~r~" + getName() + "~w~ nicht verteidigen.", dbContext.Factions.Where(f => f.Name == getOwner()).FirstOrDefault());
          Player[] owners = NAPI.Pools.GetAllPlayers().Where(c => c.IsLoggedIn() && c.GetUser().Faction.Name == this.Owner).ToArray();
          Player[] attackers = NAPI.Pools.GetAllPlayers().Where(c => c.IsLoggedIn() && c.GetUser().Faction.Name == this.Attacker).ToArray();
          foreach (var o in owners)
          {
            o.TriggerEvent("CLIENT:loose");
          }
          foreach (var a in attackers)
          {
            a.TriggerEvent("CLIENT:win");
          }
          this.Owner = FactionName;
          ChatService.BroadcastFaction("~y~[GANGWAR] ~w~Deine Fraktion konnte erfolgreich das Gebiet ~g~" + getName() + "~w~ erobern.", dbContext.Factions.Where(f => f.Name == getOwner()).FirstOrDefault());
          Turfs turf = dbContext.Turfs.Where(t => t.Id == getId()).FirstOrDefault();
          turf.Owner = this.Owner;
          turf.FactionId = dbContext.Factions.Where(f => f.Name == this.Owner).FirstOrDefault().Id;
          dbContext.SaveChanges();
        }

      }
      this.Attacker = null;
      foreach (var c in playerInGangwar)
      {
        c.TriggerEvent("CLIENT:setAttackBlip", false, TurfID);
        c.ResetData("inGangWar");
        c.ResetData("GotInsideOfTurf");
      }
      this.playerInGangwar = null;
      Gangwar.loadTurfs();
      Gangwar.loadTurfs_ToAllPlayers();
    }

    public void attack(string attacker)
    {
      Player[] usersInGangwar;
      using (var context = new DatabaseContext())
      {
        var onlinePlayers = NAPI.Pools.GetAllPlayers().Where(c => c.IsLoggedIn()).Select(c => c.Name);

        List<Player> ownersInGangwar = context.Users.Include(u => u.Faction).Where(u => onlinePlayers.Contains(u.Name) && u.Faction.Name == getOwner()).Select(u => u.Player).ToList();
        List<Player> attackersInGangwar = context.Users.Include(u => u.Faction).Where(u => onlinePlayers.Contains(u.Name) && u.Faction.Name == attacker).Select(u => u.Player).ToList();

        if (ownersInGangwar.Count < 1 && attackersInGangwar.Count < 1)
        {
          List<Player> leaders = context.Users.Include(u => u.Faction).Where(u => onlinePlayers.Contains(u.Name) && u.Faction.Name == attacker && u.FactionLeader).Select(u => u.Player).ToList();
          foreach(var l in leaders)
          {
            ChatService.ErrorMessage(l, "Gangwarstart ist nicht möglich, da die beteiligten Fraktionen nicht genügend Mitglieder aufweisen.");
          }
          
          return;
        }
        List<Player> inGangwar = new List<Player>(ownersInGangwar.Concat(attackersInGangwar));
        

        usersInGangwar = inGangwar.ToArray();
      }
      if (this.status == "normal")
      {
        if (this.timer != null)
        {
          this.timer.Stop();
          this.timer = null;
        }
        this.Attacker = attacker;
        this.status = "attack";

        List<Player> clientsInGangwar = new List<Player>();

        foreach (var u in usersInGangwar)
        {
          u.TriggerEvent("CLIENT:setAttackBlip", true, TurfID);
          u.TriggerEvent("GangwarScore", this.Attacker, this.Owner, this.Att_Score, this.Def_Score);
          u.SetData("inGangWar", getId());
          ChatService.SendMessage(u, "~y~[GANGWAR]~w~ Die " + getAttacker() + " haben das Gebiet ~y~" + TurfName + "~w~ der " + getOwner() + " angegriffen.");
          clientsInGangwar.Add(u);
        }
        playerInGangwar = clientsInGangwar.ToArray();
        NAPI.ClientEvent.TriggerClientEventForAll("CLIENT:Turf_Update", JsonConvert.SerializeObject(this.TurfID), JsonConvert.SerializeObject(this.status), JsonConvert.SerializeObject(this.Owner), JsonConvert.SerializeObject(this.Attacker));
        this.TurfTick();
      }
    }

    public void setKill(string FactionName)
    {
      if (getOwner() == FactionName)
      {
        Def_Score -= 1;
      }
      else if (getAttacker() == FactionName)
      {
        Att_Score -= 1;
      }
    }
  }
}
