using RioJoy.Core.Editing;
using RioJoy.Core.Mapping;
using Xunit;

namespace RioJoy.Core.Tests.Editing;

public class CockpitPanelTests
{
    [Fact]
    public void Covers_EveryValidAddress_ExactlyOnce()
    {
        List<int> addrs = CockpitPanel.Buttons().Select(b => b.Address).ToList();

        // 0x00–0x47 buttons + 0x50–0x6F keypads = 104 valid addresses; 0x48–0x4F don't exist.
        var expected = Enumerable.Range(0x00, 0x48).Concat(Enumerable.Range(0x50, 0x20)).ToHashSet();
        Assert.Equal(expected.Count, addrs.Count);                 // no duplicates / no extras
        Assert.Equal(expected, addrs.ToHashSet());                 // exactly the valid set
        Assert.DoesNotContain(0x48, addrs);                        // gap excluded
    }

    [Theory]
    [InlineData(0x2F, "Upper Left MFD")]
    [InlineData(0x20, "Upper Middle MFD")]
    [InlineData(0x37, "Upper Right MFD")]
    [InlineData(0x00, "Lower Right MFD")]
    [InlineData(0x0F, "Lower Left MFD")]
    [InlineData(0x38, "Throttle")]
    [InlineData(0x10, "Secondary")]
    [InlineData(0x18, "Screen")]
    [InlineData(0x40, "Joystick")]
    [InlineData(0x50, "Internal Keypad")]
    [InlineData(0x6F, "External Keypad")]
    public void Address_LandsInExpectedGroup(int address, string group)
    {
        PanelButton b = CockpitPanel.Buttons().Single(x => x.Address == address);
        Assert.Equal(group, b.Group.Title);
    }

    [Fact]
    public void Keypads_AreNotLampCapable()
    {
        foreach (PanelButton b in CockpitPanel.Buttons().Where(x => x.Group.Kind == PanelGroupKind.Keypad))
            Assert.False(b.LampCapable);
        // ...and everything else is.
        foreach (PanelButton b in CockpitPanel.Buttons().Where(x => x.Group.Kind != PanelGroupKind.Keypad))
            Assert.True(b.LampCapable);
    }

    [Fact]
    public void Keypad_PhysicalLayout_MapsDigitsToAddresses()
    {
        // Internal keypad: top-left "1" -> 0x51, bottom-middle "0" -> 0x50, "C" -> 0x5C.
        IList<PanelButton> all = CockpitPanel.Buttons();
        PanelGroup pad = CockpitPanel.Groups.Single(g => g.Title == "Internal Keypad");

        Assert.Equal(0x51, pad.Addresses[0]);  // row0 col0 = "1"
        Assert.Equal(0x5C, pad.Addresses[3]);  // row0 col3 = "C"
        Assert.Equal(0x50, pad.Addresses[13]); // row3 col1 = "0"
        Assert.Equal(0x5F, pad.Addresses[15]); // row3 col3 = "F"
    }

    [Fact]
    public void AllAddresses_AreValidRioAddresses()
    {
        foreach (PanelButton b in CockpitPanel.Buttons())
            Assert.InRange(b.Address, 0, RioAddress.MaxAddress);
    }
}
