namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

public sealed class LegacyOverseasParityWebTests
{
    private static readonly string RepositoryRoot = FindRepositoryRoot();
    private static readonly string WebRoot = Path.Combine(
        RepositoryRoot,
        "src",
        "MBN_STOCK_WEBVIEW.LegacyParityApp",
        "Web");
    private static readonly string App = File.ReadAllText(Path.Combine(WebRoot, "app.js"));
    private static readonly string Styles = File.ReadAllText(Path.Combine(WebRoot, "styles.css"));

    [Fact]
    public void OverseasTabUsesTheOriginalThreeVerticalGroups()
    {
        var render = Section("function renderOverseas(state)", "function renderComparison(state)");

        Assert.Contains("overseas-fixed-group", render, StringComparison.Ordinal);
        Assert.Contains("overseas-search-group", render, StringComparison.Ordinal);
        Assert.Contains("\uD574\uC678\uC9C0\uC218", render, StringComparison.Ordinal);
        Assert.Contains("\uD574\uC678 \uC5C5\uC885\uC9C0\uC218", render, StringComparison.Ordinal);
        Assert.Contains("\uD574\uC678 \uC885\uBAA9", render, StringComparison.Ordinal);
        Assert.Contains("\uC5C5\uC885 \uAC80\uC0C9", render, StringComparison.Ordinal);
        Assert.Contains("\uC885\uBAA9 \uAC80\uC0C9", render, StringComparison.Ordinal);
        Assert.Contains("\u0031\uC5F4\uD310", render, StringComparison.Ordinal);
        Assert.Contains("periodButtons(\"fixedIndex\")", render, StringComparison.Ordinal);
        Assert.Contains("periodButtons(kind)", render, StringComparison.Ordinal);
        Assert.Contains("model.isTruncated === true", render, StringComparison.Ordinal);
        Assert.Contains("검색 결과가 안전 상한을 초과해 일부만 표시됩니다.", render, StringComparison.Ordinal);
        Assert.Contains("표시명 없음 ", render, StringComparison.Ordinal);
        Assert.DoesNotContain("최대 500건", render, StringComparison.Ordinal);
        Assert.Contains("overseas-truncation", Styles, StringComparison.Ordinal);
        Assert.DoesNotContain("overseas-action-panel", render, StringComparison.Ordinal);
        Assert.DoesNotContain("overseas-selected", render, StringComparison.Ordinal);
        Assert.DoesNotContain("overseas-note", render, StringComparison.Ordinal);
        Assert.DoesNotContain("document.createElement(\"details\")", render, StringComparison.Ordinal);

        foreach (var selector in new[]
                 {
                     ".overseas-workspace",
                     ".overseas-fixed-body",
                     ".overseas-period-actions",
                     ".overseas-result-area",
                     ".overseas-results"
                 })
        {
            Assert.Contains(selector, Styles, StringComparison.Ordinal);
        }
    }

    [Fact]
    public void OverseasRowsSelectImmediatelyAndOnlyDispatchOpaqueNativeIdentifiers()
    {
        var render = Section("function renderOverseas(state)", "function renderComparison(state)");
        var click = Section(
            "categoryTree.addEventListener(\"click\"",
            "categoryTree.addEventListener(\"change\"");
        var overseasClick = click[click.IndexOf(
            "const overseasTarget = event.target.closest(\"button[data-overseas-target-id]\");",
            StringComparison.Ordinal)..click.IndexOf("const comparisonChoice", StringComparison.Ordinal)];
        var updater = Section("function updateOverseasWorkspace", "function markOverseasRowSelected");

        Assert.Contains("function selectOverseasRow(row)", App, StringComparison.Ordinal);
        Assert.Contains("markOverseasRowSelected(row);", App, StringComparison.Ordinal);
        Assert.Contains("selectOverseasRow(overseasTarget);", overseasClick, StringComparison.Ordinal);
        Assert.Contains("selectOverseasRow(overseasResult);", overseasClick, StringComparison.Ordinal);
        Assert.DoesNotContain("setTimeout", overseasClick, StringComparison.Ordinal);
        Assert.Contains("existingWorkspace && structureKey === overseasRenderStructureKey", render,
            StringComparison.Ordinal);
        Assert.Contains("updateOverseasWorkspace(existingWorkspace, overseas", render,
            StringComparison.Ordinal);
        Assert.DoesNotContain("categoryTree.replaceChildren", updater, StringComparison.Ordinal);

        foreach (var intent in new[]
                 {
                     "select-overseas-fixed-index",
                     "search-overseas-industries",
                     "search-overseas-stocks",
                     "select-overseas-industry",
                     "select-overseas-stock",
                     "activate-overseas-action"
                 })
        {
            Assert.Contains($"\"{intent}\"", App, StringComparison.Ordinal);
        }

        Assert.DoesNotContain("nationCode", render, StringComparison.Ordinal);
        Assert.DoesNotContain("FOREIGN_", render, StringComparison.Ordinal);
        Assert.DoesNotContain("symbol", render, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("event.key === \"Enter\"", App, StringComparison.Ordinal);
    }

    [Fact]
    public void OverseasListsUseOneTabStopAndNativeSingleSelectionKeyboardSemantics()
    {
        var helper = Section("function moveOverseasListSelection", "function renderOverseas(state)");
        var keyDown = Section(
            "categoryTree.addEventListener(\"keydown\"",
            "window.addEventListener(\"pointerup\"");

        Assert.Contains("list.getAttribute(\"aria-disabled\") === \"true\"", helper,
            StringComparison.Ordinal);
        Assert.Contains("list.querySelectorAll(\"button\")", helper, StringComparison.Ordinal);
        Assert.Contains("selectOverseasRow(nextRow);", helper, StringComparison.Ordinal);
        Assert.Contains("nextRow.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });",
            helper,
            StringComparison.Ordinal);
        Assert.Contains("const overseasList = event.target.closest(\"[data-overseas-list]\");",
            keyDown,
            StringComparison.Ordinal);
        Assert.Contains("event.stopPropagation();", keyDown, StringComparison.Ordinal);
        Assert.Contains("moveOverseasListSelection(overseasList, event.key);", keyDown,
            StringComparison.Ordinal);
        Assert.Contains("button.tabIndex = -1;", App, StringComparison.Ordinal);
        Assert.Contains("fixedList.tabIndex = 0;", App, StringComparison.Ordinal);
        Assert.Contains("list.tabIndex = 0;", App, StringComparison.Ordinal);
    }

    private static string Section(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, $"Unable to locate {startToken} section.");
        return App[start..end];
    }

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

            current = current.Parent;
        }

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