using ReallifeGamemode.Database.Entities;
using ReallifeGamemode.Database.Models;
using ReallifeGamemode.Server.Core.API;
using ReallifeGamemode.Server.Types;
using System.Collections.Generic;
using System.Linq;
using ReallifeGamemode.Server.Common;

namespace ReallifeGamemode.Server.Core.Managers
{
  class InteriorManager : Script
  {
    public static Dictionary<int, ITextLabel> _interiorEnterTextLabels = new Dictionary<int, ITextLabel>();
    public static Dictionary<int, ITextLabel> _interiorExitTextLabels = new Dictionary<int, ITextLabel>();
    public static Dictionary<int, IMarker> _interiorEnterMarkers = new Dictionary<int, IMarker>();
    public static Dictionary<int, IMarker> _interiorExitMarkers = new Dictionary<int, IMarker>();
    public static Dictionary<int, IColShape> _interiorEnterColShapes = new Dictionary<int, IColShape>();
    public static Dictionary<int, IColShape> _interiorExitColShapes = new Dictionary<int, IColShape>();

    public InteriorManager()
    {
      LoadInteriors();

      EventHandler.RegisterClientEvent("InteriorManager_UseTeleport", InteriorManagerUseTeleportEvent);
    }

    public Interior GetInteriorByName(string name, DatabaseContext dbContext)
    {
      return dbContext.Interiors.Where(i => i.Name.ToLower() == name.ToLower()).FirstOrDefault();
    }

    public Interior GetInteriorById(int id, DatabaseContext dbContext)
    {
      return dbContext.Interiors.Where(i => i.Id == id).FirstOrDefault();
    }

    public void LoadInteriors()
    {
      using var dbContext = GetDbContext();
      foreach (Interior interior in dbContext.Interiors)
      {
        LoadInterior(interior);
      }
    }

    public void LoadInterior(Interior interior)
    {
      if (interior.EnterPosition != null)
      {
        _interiorEnterTextLabels[interior.Id] = Api.TextLabel.CreateTextLabel("~y~" + interior.Name + "\n~s~Eingang", interior.EnterPosition, 10f, 1f, 0, new Color(255, 255, 255));
        _interiorEnterMarkers[interior.Id] = Api.Marker.CreateMarker(MarkerType.VerticalCylinder, interior.EnterPosition.Subtract(new Position(0, 0, 1.7)), new Position(), new Position(), 1.6f, Color.White);
        _interiorEnterColShapes[interior.Id] = Api.ColShape.CreateSphere(interior.EnterPosition, 1.5f);

        _interiorEnterColShapes[interior.Id].OnEntityEnter += InteriorManagerPlayerEnterColshapeEvent;
        _interiorEnterColShapes[interior.Id].OnEntityExit += InteriorManagerPlayerExitColshapeEvent;
      }

      if (interior.ExitPosition != null)
      {
        _interiorExitTextLabels[interior.Id] = Api.TextLabel.CreateTextLabel("~y~" + interior.Name + "\n~s~Ausgang", interior.ExitPosition, 10f, 1f, 0, new Color(255, 255, 255));
        _interiorExitMarkers[interior.Id] = Api.Marker.CreateMarker(MarkerType.VerticalCylinder, interior.ExitPosition.Subtract(new Position(0, 0, 1.7)), new Position(), new Position(), 1.6f, Color.White);
        _interiorExitColShapes[interior.Id] = Api.ColShape.CreateSphere(interior.ExitPosition, 1.5f);

        _interiorExitColShapes[interior.Id].OnEntityEnter += InteriorManagerPlayerEnterColshapeEvent;
        _interiorExitColShapes[interior.Id].OnEntityExit += InteriorManagerPlayerExitColshapeEvent;
      }
    }

    public void DeleteInterior(Interior interior)
    {
      ITextLabel enT = GetInteriorEnterTextLabel(interior);
      ITextLabel exT = GetInteriorExitTextLabel(interior);
      IMarker enM = GetInteriorEnterMarker(interior);
      IMarker exM = GetInteriorExitMarkers(interior);
      IColShape enC = GetInteriorEnterColShape(interior);
      IColShape exC = GetInteriorExitColShape(interior);

      if (enT != null) enT.Remove();
      if (exT != null) exT.Remove();
      if (enM != null) enM.Remove();
      if (exM != null) exM.Remove();
      if (enC != null) enC.Remove();
      if (exC != null) exC.Remove();

      _interiorEnterTextLabels.Remove(interior.Id);
      _interiorExitTextLabels.Remove(interior.Id);
      _interiorEnterMarkers.Remove(interior.Id);
      _interiorExitMarkers.Remove(interior.Id);
      _interiorEnterColShapes.Remove(interior.Id);
      _interiorExitColShapes.Remove(interior.Id);
    }

    public ITextLabel GetInteriorEnterTextLabel(Interior interior) => _interiorEnterTextLabels.FirstOrDefault(x => x.Key == interior.Id).Value;
    public ITextLabel GetInteriorExitTextLabel(Interior interior) => _interiorExitTextLabels.FirstOrDefault(x => x.Key == interior.Id).Value;

    public IMarker GetInteriorEnterMarker(Interior interior) => _interiorEnterMarkers.FirstOrDefault(x => x.Key == interior.Id).Value;
    public IMarker GetInteriorExitMarkers(Interior interior) => _interiorExitMarkers.FirstOrDefault(x => x.Key == interior.Id).Value;

    public IColShape GetInteriorEnterColShape(Interior interior) => _interiorEnterColShapes.FirstOrDefault(x => x.Key == interior.Id).Value;
    public IColShape GetInteriorExitColShape(Interior interior) => _interiorExitColShapes.FirstOrDefault(x => x.Key == interior.Id).Value;

    public int GetInteriorIdFromEnterColShape(IColShape handle) => _interiorEnterColShapes.FirstOrDefault(c => c.Value == handle).Key;
    public int GetInteriorIdFromExitColShape(IColShape handle) => _interiorExitColShapes.FirstOrDefault(c => c.Value == handle).Key;

    public void InteriorManagerPlayerEnterColshapeEvent(IColShape colShape, IPlayer player)
    {
      using var dbContext = GetDbContext();

      int enterId = GetInteriorIdFromEnterColShape(colShape);
      int exitId = GetInteriorIdFromExitColShape(colShape);
      if (enterId != 0)
      {
        Interior interior = GetInteriorById(enterId, dbContext);
        player.TriggerEvent("InteriorManager_ShowHelpText", interior.Name, interior.Id, 0);
      }
      else if (exitId != 0)
      {
        Interior interior = GetInteriorById(exitId, dbContext);
        player.TriggerEvent("InteriorManager_ShowHelpText", interior.Name, interior.Id, 1);
      }
    }

    public void InteriorManagerPlayerExitColshapeEvent(IColShape colShape, IPlayer player)
    {
      if (GetInteriorIdFromEnterColShape(colShape) != 0 || GetInteriorIdFromExitColShape(colShape) != 0)
      {
        player.TriggerEvent("InteriorManager_ClearHelpText");
      }
    }

    public void InteriorManagerUseTeleportEvent(IPlayer player, params object[] args)
    {
      var id = args[0].ToInt();
      var enterExit = args[1].ToInt();

      Interior interior = GetInteriorById(id, GetDbContext());

      if (interior.ExitPosition == null || interior.EnterPosition == null)
      {
        player.SendMessage("Dieses Interior ist noch nicht eingerichtet (keine Ein-/Ausgangsposition)", ChatPrefix.Error);
        return;
      }

      player.Position = enterExit == 0 ? interior.ExitPosition : interior.EnterPosition;
    }

    public IEnumerable<(string, int)> GetInteriors()
    {
      using var dbContext = GetDbContext();
      foreach (Interior interior in dbContext.Interiors)
      {
        yield return (interior.Name, interior.Id);
      }
    }
  }
}
