using Engine.Input;
using OpenTK.Mathematics;

namespace PresenterConsole;

public class ConsoleInputHandler : IInputHandler
{
  public Vector2 MousePosition => Vector2.Zero;

  private readonly bool[] _currentKeys = new bool[256];
  private readonly bool[] _previousKeys = new bool[256];

  public void Update(double parDeltaTime)
  {
    for (var i = 0; i < _currentKeys.Length; i++)
    {
      _previousKeys[i] = _currentKeys[i];
      _currentKeys[i] = (WindowsFFI.GetAsyncKeyState(i) & 0x8000) != 0;
    }
  }

  public bool IsKeyPressed(KeyboardButtonCode parKeyboardButtonCode)
  {
    var consoleKey = ConvertToConsoleKey(parKeyboardButtonCode);
    return _currentKeys[consoleKey];
  }

  public bool IsKeyJustPressed(KeyboardButtonCode parKeyboardButtonCode)
  {
    var consoleKey = ConvertToConsoleKey(parKeyboardButtonCode);
    return _currentKeys[consoleKey] && !_previousKeys[consoleKey];
  }

  public bool IsMouseButtonPressed(MouseButtonCode parButtonCode)
  {
    var consoleKey = ConvertToConsoleKey(parButtonCode);
    return _currentKeys[consoleKey];
  }

  public bool IsMouseButtonJustPressed(MouseButtonCode parButtonCode)
  {
    var consoleKey = ConvertToConsoleKey(parButtonCode);
    return _currentKeys[consoleKey] && !_previousKeys[consoleKey];
  }

  private static int ConvertToConsoleKey(MouseButtonCode parMouseButtonCode) =>
    parMouseButtonCode switch
    {
      MouseButtonCode.Left => 0x01,
      MouseButtonCode.Right => 0x02,
      MouseButtonCode.Middle => 0x04,
      _ => throw new ArgumentOutOfRangeException(nameof(parMouseButtonCode), parMouseButtonCode, null)
    };

  private static int ConvertToConsoleKey(KeyboardButtonCode parKeyboardButtonCode) =>
    parKeyboardButtonCode switch
    {
      KeyboardButtonCode.A => 0x41,
      KeyboardButtonCode.B => 0x42,
      KeyboardButtonCode.C => 0x43,
      KeyboardButtonCode.D => 0x44,
      KeyboardButtonCode.E => 0x45,
      KeyboardButtonCode.F => 0x46,
      KeyboardButtonCode.G => 0x47,
      KeyboardButtonCode.H => 0x48,
      KeyboardButtonCode.I => 0x49,
      KeyboardButtonCode.J => 0x4A,
      KeyboardButtonCode.K => 0x4B,
      KeyboardButtonCode.L => 0x4C,
      KeyboardButtonCode.M => 0x4D,
      KeyboardButtonCode.N => 0x4E,
      KeyboardButtonCode.O => 0x4F,
      KeyboardButtonCode.P => 0x50,
      KeyboardButtonCode.Q => 0x51,
      KeyboardButtonCode.R => 0x52,
      KeyboardButtonCode.S => 0x53,
      KeyboardButtonCode.T => 0x54,
      KeyboardButtonCode.U => 0x55,
      KeyboardButtonCode.V => 0x56,
      KeyboardButtonCode.W => 0x57,
      KeyboardButtonCode.X => 0x58,
      KeyboardButtonCode.Y => 0x59,
      KeyboardButtonCode.Z => 0x5A,
      KeyboardButtonCode.Enter => 0x0D,
      KeyboardButtonCode.Escape => 0x1B,
      KeyboardButtonCode.Space => 0x20,
      KeyboardButtonCode.Tab => 0x09,
      KeyboardButtonCode.Backspace => 0x08,
      KeyboardButtonCode.Up => 0x26,
      KeyboardButtonCode.Down => 0x28,
      KeyboardButtonCode.Left => 0x25,
      KeyboardButtonCode.Right => 0x27,
      KeyboardButtonCode.Shift => 0x10,
      KeyboardButtonCode.Ctrl => 0x11,
      KeyboardButtonCode.Alt => 0x12,
      KeyboardButtonCode.Delete => 0x2E,
      KeyboardButtonCode.Insert => 0x2D,
      KeyboardButtonCode.Home => 0x24,
      KeyboardButtonCode.End => 0x23,
      KeyboardButtonCode.PageUp => 0x21,
      KeyboardButtonCode.PageDown => 0x22,
      KeyboardButtonCode.D0 => 0x30,
      KeyboardButtonCode.D1 => 0x31,
      KeyboardButtonCode.D2 => 0x32,
      KeyboardButtonCode.D3 => 0x33,
      KeyboardButtonCode.D4 => 0x34,
      KeyboardButtonCode.D5 => 0x35,
      KeyboardButtonCode.D6 => 0x36,
      KeyboardButtonCode.D7 => 0x37,
      KeyboardButtonCode.D8 => 0x38,
      KeyboardButtonCode.D9 => 0x39,
      _ => throw new ArgumentOutOfRangeException(nameof(parKeyboardButtonCode), parKeyboardButtonCode, null)
    };
}