using System;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
using Quik.OpenGL;
using Quik.CommandMachine;
using Quik.PAL;
using Quik.VertexGenerator;

namespace Quik.OpenTK
{
    public class OpenTKPort : IQuikPortHandle
    {
        private readonly NativeWindow _window;
        private readonly GL21Driver _glDriver;
        private readonly VertexGeneratorEngine _vertexEngine;

        public string Title
        {
            get => _window.Title;
            set => _window.Title = value;
        }

        public QVec2 Size
        {
            get
            {
                Vector2i size = _window.ClientSize;
                return new QVec2(size.X, size.Y);
            }
            set
            {
                // OpenTK being OpenTK as usual, you can't set the client size.
                Vector2i extents = _window.Size - _window.ClientSize;
                Vector2i size = extents + new Vector2i((int)value.X, (int)value.Y);
                _window.Size = size;
            }
        }
        public QVec2 Position
        {
            get
            {
                Vector2i location = _window.Location;
                return new QVec2(location.X, location.Y);
            }
            set
            {
                Vector2i location = new Vector2i((int)value.X, (int)value.Y);
                _window.Location = location;
            }
        }

        public bool IsValid => !isDisposed;

        public event EventHandler EventRaised;

        public OpenTKPort(NativeWindow window)
        {
            _window = window;
            _glDriver = new GL21Driver();
            _vertexEngine = new VertexGeneratorEngine();
        }

        public void Focus()
        {
            _window.Focus();
        }

        public void Paint(CommandList queue)
        {
            QRectangle view = new QRectangle(Size, new QVec2(0, 0));

            _vertexEngine.Reset();
            _vertexEngine.ProcessCommands(view, queue);

            if (!_window.Context.IsCurrent)
                _window.Context.MakeCurrent();

            if (!_glDriver.IsInit)
                _glDriver.Init();

            _glDriver.Draw(_vertexEngine.DrawQueue, view);

            _window.Context.SwapBuffers();
        }

        public void Show(bool shown = true)
        {
            _window.IsVisible = shown;
        }

        private bool isDisposed;
        private void Dispose(bool disposing)
        {
            if (isDisposed) return;

            if (disposing)
            {
                _window?.Dispose();
                GC.SuppressFinalize(this);
            }

            isDisposed = true;
        }
        public void Dispose() => Dispose(true);
    }
}