namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

public sealed class LegacyRowDoubleClickParityTests
{
    private static readonly string RepositoryRoot = FindRepositoryRoot();
    private static readonly string App = File.ReadAllText(Path.Combine(
        RepositoryRoot,
        "src",
        "MBN_STOCK_WEBVIEW.LegacyParityApp",
        "Web",
        "app.js"));
    private static readonly string MainWindow = File.ReadAllText(Path.Combine(
        RepositoryRoot,
        "src",
        "MBN_STOCK_WEBVIEW.LegacyParityApp",
        "MainWindow.xaml.cs"));

    [Fact]
    public void GraphE_double_click_sends_one_opaque_atomic_command()
    {
        var handler = Extract(
            "manualWorkspace.addEventListener(\"dblclick\"",
            "manualWorkspace.addEventListener(\"click\"");

        Assert.Contains("send(\"activate-manual-financial-result\"", handler,
            StringComparison.Ordinal);
        Assert.Contains("resultId: row.dataset.manualResultId", handler,
            StringComparison.Ordinal);
        Assert.DoesNotContain("load-manual-financial", handler, StringComparison.Ordinal);
        Assert.DoesNotContain("actionId", handler, StringComparison.Ordinal);
        Assert.Contains("clearDelayedClick(manualResultClickTimer)", handler,
            StringComparison.Ordinal);
    }

    [Fact]
    public void Theme_double_click_is_atomic_and_cancels_the_delayed_single_click()
    {
        var doubleClick = Extract(
            "categoryTree.addEventListener(\"dblclick\"",
            "categoryTree.addEventListener(\"click\"");
        var clickDelegate = Extract(
            "categoryTree.addEventListener(\"click\"",
            "categoryTree.addEventListener(\"change\"");
        var themeClickStart = clickDelegate.IndexOf(
            "const themeResult = event.target.closest(\"button[data-theme-result-id]\");",
            StringComparison.Ordinal);
        var themeClickEnd = clickDelegate.IndexOf(
            "if (event.target.closest(\"button[data-theme-search]\"))",
            themeClickStart,
            StringComparison.Ordinal);
        Assert.True(themeClickStart >= 0 && themeClickEnd > themeClickStart);
        var themeClick = clickDelegate[themeClickStart..themeClickEnd];

        Assert.Contains("send(\"activate-theme-result\"", doubleClick,
            StringComparison.Ordinal);
        Assert.DoesNotContain("send(\"select-theme\"", doubleClick,
            StringComparison.Ordinal);
        Assert.Contains("clearDelayedClick(themeResultClickTimer)", doubleClick,
            StringComparison.Ordinal);
        Assert.Contains(
            "if (send(\"select-theme\", { resultId: resultId }))",
            themeClick,
            StringComparison.Ordinal);
        Assert.Contains("beginThemeResultPendingSelection(themeResult)", themeClick,
            StringComparison.Ordinal);
        Assert.Contains("clearThemeResultPendingSelection(true)", themeClick,
            StringComparison.Ordinal);
        Assert.Contains("clearDelayedClick(themeResultClickTimer)", themeClick,
            StringComparison.Ordinal);
        Assert.Contains("themeResultClickTimer = deferLegacySingleClick", themeClick,
            StringComparison.Ordinal);
    }

    [Fact]
    public void Named_playlist_double_click_uses_id_bound_commands_and_closes_after_receipt_only()
    {
        var doubleClick = Extract(
            "namedPlaylistDefinitions.addEventListener(\"dblclick\"",
            "namedPlaylistDefinitions.addEventListener(\"click\"");
        var action = Extract(
            "function runNamedPlaylistDoubleClick",
            "function lockNamedPlaylistControls");
        var confirmation = Extract(
            "function resolveNamedPlaylistConfirmation",
            "function renderNamedPlaylist");
        var matcher = Extract(
            "function isMatchingNamedPlaylistReceipt",
            "function openNamedPlaylistConfirmation");
        var render = Extract("function renderNamedPlaylist", "function renderOperatorCatalog");

        Assert.Contains("namedPlaylistSelection.defer", doubleClick,
            StringComparison.Ordinal);
        Assert.Contains("runNamedPlaylistDoubleClick", doubleClick,
            StringComparison.Ordinal);
        Assert.Contains("\"load-named-playlist-by-id\"", action,
            StringComparison.Ordinal);
        Assert.Contains("openNamedPlaylistConfirmation", action,
            StringComparison.Ordinal);
        Assert.Contains("message: \"저장하겠습니까?\"", action,
            StringComparison.Ordinal);
        Assert.Contains("showSavedAlert: false", action, StringComparison.Ordinal);
        Assert.Contains("closeOnNo: true", action, StringComparison.Ordinal);
        Assert.DoesNotContain("window.confirm", action + doubleClick, StringComparison.Ordinal);
        Assert.Contains("\"save-current-named-playlist-to\"", confirmation,
            StringComparison.Ordinal);
        Assert.DoesNotContain("select-named-playlist", doubleClick, StringComparison.Ordinal);
        Assert.Contains("commandResult.succeeded === true", render, StringComparison.Ordinal);
        Assert.Contains("commandResult.targetId === pending.targetId",
            matcher,
            StringComparison.Ordinal);
        Assert.Contains("closeNamedPlaylist()", render, StringComparison.Ordinal);
    }

    [Fact]
    public void Native_dispatch_awaits_all_atomic_read_then_materialize_commands()
    {
        foreach (var method in new[]
                 {
                     "ActivateManualFinancialResultAsync(",
                     "ActivateThemeResultAsync(",
                     "LoadNamedPlaylistByIdAsync(",
                     "SaveCurrentNamedPlaylistToAsync("
                 })
        {
            Assert.Contains(method, MainWindow, StringComparison.Ordinal);
        }
    }

    private static string Extract(string startToken, string endToken)
    {
        var start = App.IndexOf(startToken, StringComparison.Ordinal);
        var end = App.IndexOf(endToken, start + startToken.Length, StringComparison.Ordinal);
        Assert.True(start >= 0 && end > start);
        return App[start..end];
    }

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

            current = current.Parent;
        }

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