using System.Text.RegularExpressions;

namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

public sealed class LegacyExplicitModalExitContractTests
{
    private static readonly string RepositoryRoot = FindRepositoryRoot();
    private static readonly string WebRoot = Path.Combine(
        RepositoryRoot,
        "src",
        "MBN_STOCK_WEBVIEW.LegacyParityApp",
        "Web");
    private static readonly string Markup = File.ReadAllText(Path.Combine(WebRoot, "index.html"));
    private static readonly string App = File.ReadAllText(Path.Combine(WebRoot, "app.js"));
    private static readonly string Styles = File.ReadAllText(Path.Combine(WebRoot, "styles.css"));
    private static readonly string ModalFocus = File.ReadAllText(
        Path.Combine(WebRoot, "legacy-modal-focus.js"));
    private static readonly string InputSmoke = File.ReadAllText(Path.Combine(
        RepositoryRoot,
        "scripts",
        "Test-LegacyPackageInput.mjs"));

    [Theory]
    [InlineData(
        "manual-financial-workspace",
        "manual-financial-exit",
        "나가기")]
    [InlineData(
        "manual-list-workspace",
        "manual-list-cancel",
        "취소")]
    public void Original_text_exit_is_a_focusable_footer_button(
        string workspaceId,
        string buttonId,
        string label)
    {
        Assert.Matches(
            $"id=\"{workspaceId}\"[\\s\\S]*?<footer class=\"manual-dialog-footer\">" +
            $"\\s*<button id=\"{buttonId}\" type=\"button\">{label}</button>",
            Markup);
        Assert.DoesNotMatch(
            $"<button id=\"{buttonId}\"[^>]*(?:disabled|tabindex=\"-1\")",
            Markup);
        Assert.Contains("\"button\"", ModalFocus, StringComparison.Ordinal);
    }

    [Theory]
    [InlineData(
        "closeManualFinancial",
        "manualClose",
        "manualExit",
        "close-manual-financial")]
    [InlineData(
        "closeManualList",
        "manualListClose",
        "manualListCancel",
        "close-manual-list")]
    public void Text_and_top_exit_share_one_close_handler(
        string handler,
        string topButton,
        string textButton,
        string intent)
    {
        Assert.Contains($"function {handler}()", App, StringComparison.Ordinal);
        Assert.Contains(
            $"{topButton}.addEventListener(\"click\", {handler})",
            App,
            StringComparison.Ordinal);
        Assert.Contains(
            $"{textButton}.addEventListener(\"click\", {handler})",
            App,
            StringComparison.Ordinal);

        var handlerStart = App.IndexOf($"function {handler}()", StringComparison.Ordinal);
        var nextListener = App.IndexOf(
            $"{topButton}.addEventListener",
            handlerStart,
            StringComparison.Ordinal);
        Assert.True(handlerStart >= 0 && nextListener > handlerStart);
        var body = App[handlerStart..nextListener];
        Assert.Single(Regex.Matches(body, $"send\\(\"{intent}\"").Cast<Match>());
    }

    [Fact]
    public void Text_exit_lock_state_tracks_the_existing_top_exit()
    {
        Assert.Contains(
            "manualExit.disabled = manualClose.disabled;",
            App,
            StringComparison.Ordinal);
        Assert.Contains(
            "manualListCancel.disabled = manualListClose.disabled;",
            App,
            StringComparison.Ordinal);
        Assert.Contains(
            "root.querySelectorAll(\"button, input, select, textarea\")",
            App,
            StringComparison.Ordinal);
        Assert.Contains(
            "setTransientControlsBusy(manualDialog, state.isBusy === true);",
            App,
            StringComparison.Ordinal);
        Assert.Contains(
            "setTransientControlsBusy(manualListDialog, busy);",
            App,
            StringComparison.Ordinal);
        Assert.Matches(
            @"\.manual-financial-dialog\s*\{[^}]*grid-template-rows:\s*46px minmax\(0, 1fr\) auto",
            Styles);
        Assert.Matches(
            @"\.manual-list-dialog\s*\{[^}]*grid-template-rows:\s*46px minmax\(0, 1fr\) auto",
            Styles);
    }

    [Fact]
    public void Full_UI_input_validation_clicks_the_restored_text_exit_controls()
    {
        Assert.Matches(
            @"async function closeManualFinancial[\s\S]*?pointerClick\('document\.getElementById\(""manual-financial-exit""\)'",
            InputSmoke);
        Assert.Matches(
            @"async function closeManualList[\s\S]*?pointerClick\('document\.getElementById\(""manual-list-cancel""\)'",
            InputSmoke);
    }

    [Theory]
    [InlineData("overseasStocks", "해외시장")]
    [InlineData("tradingHalt", "거래정지")]
    public void Clear_sidebar_name_preserves_the_existing_tab_identity(
        string tabId,
        string displayName)
    {
        var match = Regex.Match(
            Markup,
            $"<button[^>]*data-tab-id=\"{tabId}\"[\\s\\S]*?</button>");
        Assert.True(match.Success);
        Assert.Contains($"aria-label=\"{displayName}\"", match.Value,
            StringComparison.Ordinal);
        Assert.Contains($"title=\"{displayName}\"", match.Value,
            StringComparison.Ordinal);
        Assert.Contains($">{displayName}</span>", match.Value,
            StringComparison.Ordinal);
    }

    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.");
    }
}
