using System.Runtime.Versioning;
using RioJoy.Core.Editing;

namespace RioJoy.Tray.Editor;

/// <summary>
/// Interactive cockpit control-panel map: draws the functional groups (via
/// <see cref="PanelView"/>) and raises <see cref="AddressSelected"/> when a button
/// is clicked. Sized to the full panel so the host scrolls it.
/// </summary>
[SupportedOSPlatform("windows")]
internal sealed class PanelCanvas : Control
{
    private static readonly IReadOnlyList<PanelButton> AllButtons = CockpitPanel.Buttons();

    public PanelCanvas()
    {
        DoubleBuffered = true;
        BackColor = Color.FromArgb(28, 28, 28);
        Size = PanelView.GridSize(AllButtons);
    }

    /// <summary>Resolves the display label for an address (from the profile).</summary>
    public Func<int, string?>? LabelProvider { get; set; }

    /// <summary>Resolves the assigned-function caption for an address (empty = unmapped).</summary>
    public Func<int, string?>? FunctionProvider { get; set; }

    /// <summary>Whether an address's lamp is lit (the binding's IsLit flag) — drives the lamp shade.</summary>
    public Func<int, bool>? LitProvider { get; set; }

    public int? SelectedAddress { get; private set; }

    public event Action<int>? AddressSelected;

    public void Select(int? address)
    {
        SelectedAddress = address;
        Invalidate();
    }

    public void Refresh(int? address)
    {
        SelectedAddress = address;
        Invalidate();
    }

    protected override void OnPaint(PaintEventArgs e) =>
        PanelView.Paint(
            e.Graphics, AllButtons, CockpitPanel.Groups,
            a => LabelProvider?.Invoke(a),
            a => FunctionProvider?.Invoke(a),
            a => LitProvider?.Invoke(a) ?? false,
            SelectedAddress);

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        PanelButton? hit = PanelView.HitTest(AllButtons, e.Location);
        if (hit is not null)
        {
            SelectedAddress = hit.Address;
            AddressSelected?.Invoke(hit.Address);
            Invalidate();
        }
    }
}
