using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using ReallifeGamemode.Database.Models;
using ReallifeGamemode.Server.Core.API;
using ReallifeGamemode.Server.Core.Commands;
using ReallifeGamemode.Server.Log;

namespace ReallifeGamemode.Server.Core
{
  public class Main
  {
    internal static IAPI API { get; private set; }
    internal static Events.EventHandler EventHandler { get; private set; }

    private static readonly List<Script> loadedScripts = new List<Script>();

    private readonly ILogger logger = LogManager.GetLogger<Main>();

    public Main(IAPI api, Events.EventHandler eventHandler, string[] registeredCommands)
    {
      logger.LogInformation("Loading scripts...");
      API = api;
      EventHandler = eventHandler;

      DatabaseContext.LoggerFactory = LogManager.Factory;

      API.DisableDefaultCommandErrorMessages();
      API.DisableDefaultSpawnBehavior();
      API.SetGlobalChatEnabled(false);

      LoadScript();
      LoadCommands(registeredCommands);
    }

    private void LoadScript()
    {
      var allTypes = typeof(Main).Assembly.GetTypes();
      var scriptTypes = allTypes.Where(t => t.IsSubclassOf(typeof(Script)) && !t.IsAbstract);

      foreach (var scriptType in scriptTypes)
      {
        logger.LogDebug("Loading script '{FullName}'", scriptType.FullName);
        var script = Activator.CreateInstance(scriptType) as Script;
        loadedScripts.Add(script);
      }
    }

    private void LoadCommands(string[] registeredCommands)
    {
      CommandHandler commandHandler = new CommandHandler(API, registeredCommands);

      var allTypes = Assembly.GetExecutingAssembly().GetTypes();
      var commandTypes = allTypes.Where(t => t.IsSubclassOf(typeof(Command)) && !t.IsAbstract);

      foreach (var command in commandTypes)
      {
        var cmd = Activator.CreateInstance(command) as Command;
        commandHandler.RegisterCommand(cmd.CommandName, cmd);
      }
    }

    public static DatabaseContext GetDbContext(bool useLoggerFactory = true)
    {
      return new DatabaseContext(useLoggerFactory);
    }

    internal static TScript GetScript<TScript>() where TScript : Script
    {
      return loadedScripts.Where(s => s.GetType() == typeof(TScript)).First() as TScript;
    }
  }
}
