using System.Numerics;
using Raylib_cs;

namespace Voile.Input
{
    /// <summary>
    /// An input system implemented using Raylib's API. Used by default together with <see cref="Rendering.RaylibRenderSystem"/>.
    /// </summary>
    public class RaylibInputSystem : InputSystem
    {
        public override void Poll()
        {
            _justPressedKeys.Clear();
            _justReleasedKeys.Clear();
            _downKeys.Clear();

            _pressedMouseButtons.Clear();
            _releasedMouseButtons.Clear();
            _downMouseButtons.Clear();

            for (int key = 32; key <= 349; key++)
            {
                var k = (KeyboardKey)key;
                if (Raylib.IsKeyPressed((Raylib_cs.KeyboardKey)k)) _justPressedKeys.Add(k);
                if (Raylib.IsKeyReleased((Raylib_cs.KeyboardKey)k)) _justReleasedKeys.Add(k);
                if (Raylib.IsKeyDown((Raylib_cs.KeyboardKey)k)) _downKeys.Add(k);
            }

            foreach (MouseButton button in System.Enum.GetValues(typeof(MouseButton)))
            {
                var rayButton = (Raylib_cs.MouseButton)button;
                if (Raylib.IsMouseButtonPressed(rayButton)) _pressedMouseButtons.Add(button);
                if (Raylib.IsMouseButtonReleased(rayButton)) _releasedMouseButtons.Add(button);
                if (Raylib.IsMouseButtonDown(rayButton)) _downMouseButtons.Add(button);
            }

            _mousePosition = Raylib.GetMousePosition();
            _mouseWheelMove = Raylib.GetMouseWheelMove();
        }

        public override int GetCharPressed() => Raylib.GetCharPressed();
        public override Vector2 GetMousePosition() => _mousePosition;
        public override float GetMouseWheelMovement() => _mouseWheelMove;

        public override void HideCursor() => Raylib.HideCursor();
        public override void ShowCursor() => Raylib.ShowCursor();
        public override bool IsCursorHidden() => Raylib.IsCursorHidden();

        public override bool IsKeyboardKeyDown(KeyboardKey key) => _downKeys.Contains(key);
        public override bool KeyboardKeyJustPressed(KeyboardKey key) => _justPressedKeys.Contains(key);
        public override bool KeyboardKeyJustReleased(KeyboardKey key) => _justReleasedKeys.Contains(key);

        public override bool IsMouseButtonPressed(MouseButton button) => _pressedMouseButtons.Contains(button);
        public override bool IsMouseButtonReleased(MouseButton button) => _releasedMouseButtons.Contains(button);
        public override bool IsMouseButtonDown(MouseButton button) => _downMouseButtons.Contains(button);

        public override void SetMousePosition(Vector2 position) => Raylib.SetMousePosition((int)position.X, (int)position.Y);

        private readonly HashSet<KeyboardKey> _justPressedKeys = new();
        private readonly HashSet<KeyboardKey> _justReleasedKeys = new();
        private readonly HashSet<KeyboardKey> _downKeys = new();

        private readonly HashSet<MouseButton> _pressedMouseButtons = new();
        private readonly HashSet<MouseButton> _releasedMouseButtons = new();
        private readonly HashSet<MouseButton> _downMouseButtons = new();

        private Vector2 _mousePosition;
        private float _mouseWheelMove;
    }
}