using VRio.Core.Device;

namespace VRio.Core.Input;

/// <summary>
/// How a key drives an axis: <see cref="Deflect"/> holds the axis at the
/// binding's value while the key is down and springs back when released
/// (stick, pedals); <see cref="Rate"/> walks the axis by value-per-second
/// while held and the position sticks (throttle).
/// </summary>
public enum KeyAxisMode
{
    Deflect,
    Rate,
}

/// <summary>A keyboard key pressing a RIO input address.</summary>
/// <param name="Key">Key name as the host reports it (System.Windows.Forms
/// Keys.ToString(): "W", "Up", "NumPad1", …); matched case-insensitively.</param>
/// <param name="Address">RIO input address (button 0x00–0x47 or keypad 0x50–0x6F).</param>
/// <param name="Toggle">Latch on press instead of momentary press/release.</param>
public sealed record KeyButtonBinding(string Key, int Address, bool Toggle);

/// <summary>
/// A keyboard key driving a RIO axis in normalized units, where 1 is the
/// axis' full realistic travel (<see cref="RioAxisRange.Full"/> carries the
/// wire sign, so bindings never deal with the throttle's negative direction).
/// </summary>
/// <param name="Value">Deflect: the normalized position held while the key is
/// down. Rate: normalized units per second, signed.</param>
public sealed record KeyAxisBinding(string Key, RioAxis Axis, KeyAxisMode Mode, float Value);

/// <summary>A gamepad button pressing a RIO input address.</summary>
public sealed record PadButtonBinding(PadButtons Button, int Address, bool Toggle);

/// <summary>
/// A gamepad analog control driving a RIO axis. With <paramref name="Rate"/>
/// zero the (deadzoned, optionally inverted) pad value maps directly to the
/// normalized axis position; with a positive rate the pad value is a speed —
/// the axis integrates by value × rate per second and holds (throttle-style).
/// </summary>
public sealed record PadAxisBinding(PadAxis Source, RioAxis Axis, bool Invert, float Deadzone, float Rate);

/// <summary>An immutable set of input bindings (one parsed profile file).</summary>
public sealed class BindingProfile
{
    public static readonly BindingProfile Empty = new(
        Array.Empty<KeyButtonBinding>(), Array.Empty<KeyAxisBinding>(),
        Array.Empty<PadButtonBinding>(), Array.Empty<PadAxisBinding>());

    public BindingProfile(
        IReadOnlyList<KeyButtonBinding> keyButtons,
        IReadOnlyList<KeyAxisBinding> keyAxes,
        IReadOnlyList<PadButtonBinding> padButtons,
        IReadOnlyList<PadAxisBinding> padAxes)
    {
        KeyButtons = keyButtons;
        KeyAxes = keyAxes;
        PadButtons = padButtons;
        PadAxes = padAxes;
    }

    public IReadOnlyList<KeyButtonBinding> KeyButtons { get; }
    public IReadOnlyList<KeyAxisBinding> KeyAxes { get; }
    public IReadOnlyList<PadButtonBinding> PadButtons { get; }
    public IReadOnlyList<PadAxisBinding> PadAxes { get; }

    public int Count => KeyButtons.Count + KeyAxes.Count + PadButtons.Count + PadAxes.Count;
}
