namespace MBN_STOCK_WEBVIEW.LegacyApplication.Tests;

public sealed class LegacyCutKeyboardParityTests
{
    [Fact]
    public async Task ControlNavigationMovesOnlyFocusAndShiftKeepsTheNativeAnchor()
    {
        var controller = await CreateReadyControllerAsync();
        controller.CutPointerDown(2, false, false, 1, 47, 1_000);

        var controlDown = controller.CutKeyDown(
            LegacyCutKeyboardKey.ArrowDown,
            control: true,
            shift: false);
        var shiftSpace = controller.CutKeyDown(
            LegacyCutKeyboardKey.Space,
            control: false,
            shift: true);
        var plainDown = controller.CutKeyDown(
            LegacyCutKeyboardKey.ArrowDown,
            control: false,
            shift: false);
        var shiftUp = controller.CutKeyDown(
            LegacyCutKeyboardKey.ArrowUp,
            control: false,
            shift: true);

        AssertCutState(controlDown, [2], focused: 3);
        AssertCutState(shiftSpace, [2, 3], focused: 3);
        AssertCutState(plainDown, [4], focused: 4);
        AssertCutState(shiftUp, [3, 4], focused: 3);
    }

    [Fact]
    public async Task ControlShiftNavigationAddsRangeWithoutDiscardingExistingSelection()
    {
        var controller = await CreateReadyControllerAsync();
        controller.CutPointerDown(1, false, false, 1, 24, 1_000);
        controller.CutPointerDown(4, true, false, 1, 93, 2_000);
        controller.CutKeyDown(
            LegacyCutKeyboardKey.ArrowUp,
            control: true,
            shift: false);

        var state = controller.CutKeyDown(
            LegacyCutKeyboardKey.ArrowUp,
            control: true,
            shift: true);

        AssertCutState(state, [1, 2, 3, 4], focused: 2);
    }

    [Fact]
    public async Task HomeAndEndUsePhysicalBoundariesIncludingSeparatorRows()
    {
        var controller = await CreateReadyControllerAsync();
        controller.CutPointerDown(2, false, false, 1, 47, 1_000);

        var end = controller.CutKeyDown(
            LegacyCutKeyboardKey.End,
            control: false,
            shift: false);
        var controlHome = controller.CutKeyDown(
            LegacyCutKeyboardKey.Home,
            control: true,
            shift: false);
        var shiftSpace = controller.CutKeyDown(
            LegacyCutKeyboardKey.Space,
            control: false,
            shift: true);

        var last = end.CutRows.Count - 1;
        AssertCutState(end, [last], focused: last);
        AssertCutState(controlHome, [last], focused: 0);
        AssertCutState(shiftSpace, Enumerable.Range(0, last + 1), focused: 0);
    }

    [Fact]
    public async Task ControlSpaceTogglesFocusedRowAndMovesTheAnchor()
    {
        var controller = await CreateReadyControllerAsync();
        controller.CutPointerDown(1, false, false, 1, 24, 1_000);

        var toggledOff = controller.CutKeyDown(
            LegacyCutKeyboardKey.Space,
            control: true,
            shift: false);
        controller.CutKeyDown(
            LegacyCutKeyboardKey.ArrowDown,
            control: true,
            shift: false);
        var extended = controller.CutKeyDown(
            LegacyCutKeyboardKey.Space,
            control: false,
            shift: true);

        AssertCutState(toggledOff, [], focused: 1);
        AssertCutState(extended, [1, 2], focused: 2);
    }

    [Fact]
    public async Task KeyboardSelectionFeedsTheSameNativeDropAuthority()
    {
        var controller = await CreateReadyControllerAsync();

        var selected = controller.CutKeyDown(
            LegacyCutKeyboardKey.Space,
            control: false,
            shift: false);
        var dropped = controller.DropSelectedCutsOnPlaylist();

        AssertCutState(selected, [0], focused: 0);
        Assert.Equal(
            LegacyStockCutCatalog.Rows[0].RawLabel,
            Assert.Single(dropped.Playlist).RawCutLabel);
    }

    [Fact]
    public void KeyboardSelectionIsIgnoredUntilAStockIsSelected()
    {
        var controller = new LegacyOperatorController(new OneStockLookup());
        var before = controller.Current;

        var after = controller.CutKeyDown(
            LegacyCutKeyboardKey.End,
            control: false,
            shift: false);

        Assert.Equal(before.Revision, after.Revision);
        Assert.DoesNotContain(after.CutRows, row => row.IsFocused || row.IsSelected);
    }

    private static async Task<LegacyOperatorController> CreateReadyControllerAsync()
    {
        var controller = new LegacyOperatorController(new OneStockLookup());
        await controller.SearchStocksAsync("stock", LegacySearchTrigger.Button);
        controller.SelectStock(0);
        return controller;
    }

    private static void AssertCutState(
        LegacyOperatorSnapshot snapshot,
        IEnumerable<int> selected,
        int focused)
    {
        Assert.Equal(
            selected,
            snapshot.CutRows
                .Where(row => row.IsSelected)
                .Select(row => row.PhysicalIndex));
        Assert.Equal(
            focused,
            Assert.Single(snapshot.CutRows, row => row.IsFocused).PhysicalIndex);
    }

    private sealed class OneStockLookup : ILegacyStockLookup
    {
        public Task<LegacyStockSearchData> SearchAsync(
            string query,
            CancellationToken cancellationToken = default) =>
            Task.FromResult(new LegacyStockSearchData(
                query,
                ["Stock"],
                [new LegacyStockIdentity(
                    LegacyDomesticStockMarket.Kospi,
                    "Stock",
                    "000001")]));
    }
}
