using Engine.Graphics;
using Engine.Graphics.Texture;
using OpenTK.Graphics.OpenGL;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;

namespace Engine;

public class Window : IPresenter
{
  public bool IsExiting => _window.IsExiting;
  public int Width { get; private set; }
  public int Height { get; private set; }
  public event Action<ResizeEventArgs>? Resize;

  internal NativeWindow NativeWindow => _window;

  private readonly Engine _engine;
  private readonly NativeWindow _window;
  private readonly bool _headless;

  public Window(Engine parEngine, NativeWindow parWindow, bool parHeadless)
  {
    _engine = parEngine;
    _window = parWindow;
    _headless = parHeadless;

    (Width, Height) = _window.ClientSize;

    _window.MakeCurrent();
    _window.Resize += parArgs =>
    {
      Width = parArgs.Width;
      Height = parArgs.Height;
      Resize?.Invoke(parArgs);
    };

    _window.VSync = VSyncMode.On;
  }

  public void Update(double parDeltaTime)
  {
  }

  public void Render()
  {
    if (_headless)
    {
      return;
    }

    _window.NewInputFrame();
    NativeWindow.ProcessWindowEvents(false);
    _window.SwapBuffers();
  }

  public void Present(IConstTexture parTexture)
  {
    if (_headless)
    {
      return;
    }

    GL.BlitNamedFramebuffer(_engine.Renderer.RenderFramebuffer.Handle, 0,
      0, parTexture.Height, parTexture.Width, 0,
      0, 0, Width, Height,
      ClearBufferMask.ColorBufferBit,
      BlitFramebufferFilter.Nearest
    );
  }

  public void Exit()
  {
    _window.Close();
  }
}

public static class NativeWindowExtensions
{
  public static unsafe void SwapBuffers(this NativeWindow parWindow)
  {
    GLFW.SwapBuffers(parWindow.WindowPtr);
  }
}