using System.IO;
using System.Windows;
using Engine;
using Engine.Graphics;
using Engine.Graphics.Texture;
using Engine.Input;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using Serilog.Events;

namespace PresenterWpf;

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
  // Hijack the default startup event to start the engine
  protected override void OnStartup(StartupEventArgs parEventArgs)
  {
    var presenter = new PresenterWrapper();
    var inputHandler = new InputHandlerWrapper();
    var engine = new EngineBuilder()
      .Headless()
      .Presenter(_ => presenter)
      .InputHandler(_ => inputHandler)
      .LogToConsole()
      .LogToFile(true, "log.txt")
      .LogLevel(LogEventLevel.Debug)
      .AssetFolder(Path.GetFullPath("../DoomDeathmatch/asset"))
      .Build();

    // Since engine claims current thread for rendering, we need to create a new thread to run WPF
    var thread = new Thread(() =>
    {
      var window = new MainWindow(engine);
      presenter.Presenter = window;
      inputHandler.InputHandler = new WpfInputHandler(window);
      window.Show();
      System.Windows.Threading.Dispatcher.Run();
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.IsBackground = true;
    thread.Start();

    DoomDeathmatch.DoomDeathmatch.Initialize(engine);

    engine.Run();

    // Shutdown WPF
    Shutdown();
  }

  private class InputHandlerWrapper : IInputHandler
  {
    public Vector2 MousePosition => _inputHandler?.MousePosition ?? Vector2.Zero;

    private IInputHandler? _inputHandler;

    public IInputHandler? InputHandler
    {
      get => _inputHandler;
      set
      {
        _inputHandler = value;
      }
    }

    public bool IsKeyPressed(KeyboardButtonCode parKeyboardButtonCode)
    {
      return _inputHandler?.IsKeyPressed(parKeyboardButtonCode) ?? false;
    }

    public bool IsKeyJustPressed(KeyboardButtonCode parKeyboardButtonCode)
    {
      return _inputHandler?.IsKeyJustPressed(parKeyboardButtonCode) ?? false;
    }

    public bool IsMouseButtonPressed(MouseButtonCode parButtonCode)
    {
      return _inputHandler?.IsMouseButtonPressed(parButtonCode) ?? false;
    }

    public bool IsMouseButtonJustPressed(MouseButtonCode parButtonCode)
    {
      return _inputHandler?.IsMouseButtonJustPressed(parButtonCode) ?? false;
    }

    public void Update(double parDeltaTime)
    {
      _inputHandler?.Update(parDeltaTime);
    }
  }

  private class PresenterWrapper : IPresenter
  {
    private IPresenter? _presenter;

    public IPresenter? Presenter
    {
      get => _presenter;
      set
      {
        if (_presenter != null)
        {
          _presenter.Resize -= PresenterResize;
        }

        if (value != null)
        {
          value.Resize += PresenterResize;
        }

        _presenter = value;
      }
    }

    public bool IsExiting => Presenter?.IsExiting ?? false;
    public int Width => Presenter?.Width ?? 0;
    public int Height => Presenter?.Height ?? 0;
    public event Action<ResizeEventArgs>? Resize;

    public void Present(IConstTexture parTexture)
    {
      Presenter?.Present(parTexture);
    }

    public void Update(double parDeltaTime)
    {
      Presenter?.Update(parDeltaTime);
    }

    public void Render()
    {
      Presenter?.Render();
    }

    private void PresenterResize(ResizeEventArgs e)
    {
      Resize?.Invoke(e);
    }

    public void Exit()
    {
      Presenter?.Exit();
    }
  }
}