namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

public sealed class LegacyFsellPackageInputContractTests
{
    private static readonly string Harness = File.ReadAllText(Path.Combine(
        FindRepositoryRoot(),
        "scripts",
        "Test-LegacyPackageInput.mjs"));

    [Fact]
    public void FsellCellEditUsesPackagedPointerTextAndFocusChangeBeforeNativeDraftCheck()
    {
        var helper = Slice(
            Harness,
            "async function replaceManualNetSellCell",
            "async function confirmManualNetSellAndVerifyReadback");

        AssertInOrder(
            helper,
            "await replaceText(expression, value, label);",
            "await pressKey(\"Tab\"",
            "snapshot.state.revision > before.state.revision",
            "snapshot.state.manualLists?.netRowsAreFresh === false",
            "snapshot.state.manualLists?.writesQuarantined !== true",
            "JSON.stringify(netSellProjection(snapshot)) === JSON.stringify(expectedRows)");
        Assert.DoesNotContain("Runtime.evaluate", helper, StringComparison.Ordinal);
        Assert.DoesNotContain(".value =", helper, StringComparison.Ordinal);
    }

    [Fact]
    public void FsellSaveIsIssuedOnceAndRequiresCorrelatedFreshReadBeforeContinuing()
    {
        var helper = Slice(
            Harness,
            "async function confirmManualNetSellAndVerifyReadback",
            "function viProjection");

        Assert.Equal(
            1,
            helper.Split(
                "await pointerClick(modalButtonByTextExpression(\"확인\"), label);",
                StringSplitOptions.None).Length - 1);
        AssertInOrder(
            helper,
            "before.state.manualLists?.canSave !== true",
            "await pointerClick(modalButtonByTextExpression(\"확인\"), label);",
            "snapshot.state.manualLists?.isOpen === false",
            "snapshot.state.manualLists?.netRowsAreFresh === true",
            "snapshot.state.manualLists?.writesQuarantined !== true",
            "JSON.stringify(netSellProjection(snapshot)) === JSON.stringify(expectedRows)",
            "snapshot.state.playlist.length === before.state.playlist.length + 1");
    }

    [Fact]
    public void FsellRoundTripPersistsUniqueTemporaryValueThenRestoresExactBaseline()
    {
        var sequence = Slice(
            Harness,
            "\"fixed-245\", \"net-sell\", \"individual\", \"FSell save reopen\"");

        Assert.Contains("randomBytes(3).readUIntBE(0, 3)", sequence,
            StringComparison.Ordinal);
        Assert.Equal(
            2,
            sequence.Split("await replaceManualNetSellCell(",
                StringSplitOptions.None).Length - 1);
        Assert.Equal(
            2,
            sequence.Split("await confirmManualNetSellAndVerifyReadback(",
                StringSplitOptions.None).Length - 1);
        AssertInOrder(
            sequence,
            "temporaryRows[0].leftAmount = temporaryLeftAmount;",
            "\"FSell row 1 left amount temporary input\"",
            "\"FSell temporary value confirm save\"",
            "fsellRoundTrip.mutationSaveVerified = true;",
            "\"FSell temporary value fresh read\"",
            "fsellRoundTrip.mutationFreshReadVerified = true;",
            "individualBaseline[0].leftAmount, individualBaseline",
            "\"FSell original value confirm restore\"",
            "fsellRoundTrip.restoreSaveVerified = true;",
            "\"FSell restored fresh read\"",
            "JSON.stringify(netSellProjection(current)) !== JSON.stringify(individualBaseline)",
            "fsellRoundTrip.restoreFreshReadVerified = true;");
        Assert.Contains("restored: true", sequence, StringComparison.Ordinal);
    }

    private static string Slice(string source, string start, string? end = null)
    {
        var startIndex = source.IndexOf(start, StringComparison.Ordinal);
        Assert.True(startIndex >= 0, $"Start marker was not found: {start}");
        if (end is null)
        {
            return source[startIndex..];
        }

        var endIndex = source.IndexOf(end, startIndex, StringComparison.Ordinal);
        Assert.True(endIndex > startIndex, $"End marker was not found: {end}");
        return source[startIndex..endIndex];
    }

    private static void AssertInOrder(string source, params string[] markers)
    {
        var cursor = 0;
        foreach (var marker in markers)
        {
            var index = source.IndexOf(marker, cursor, StringComparison.Ordinal);
            Assert.True(index >= cursor, $"Marker was missing or out of order: {marker}");
            cursor = index + marker.Length;
        }
    }

    private static string FindRepositoryRoot()
    {
        var directory = new DirectoryInfo(AppContext.BaseDirectory);
        while (directory is not null)
        {
            if (File.Exists(Path.Combine(directory.FullName, "MBN_STOCK_WEBVIEW.sln")))
            {
                return directory.FullName;
            }

            directory = directory.Parent;
        }

        throw new DirectoryNotFoundException("Repository root was not found.");
    }
}
