using System.Text.RegularExpressions;

namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

public sealed class LegacyManualFinancialParityWebTests
{
    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 MainWindow = File.ReadAllText(Path.Combine(
        RepositoryRoot,
        "src",
        "MBN_STOCK_WEBVIEW.LegacyParityApp",
        "MainWindow.xaml.cs"));

    [Theory]
    [InlineData("revenue-composition", "주요매출 구성")]
    [InlineData("growth-metrics", "성장성 지표")]
    [InlineData("sales", "매출액")]
    [InlineData("operating-profit", "영업이익")]
    public void Original_left_GraphE_buttons_are_enabled_closed_screen_intents(
        string screen,
        string label)
    {
        Assert.Matches(
            $"<button(?![^>]*disabled)[^>]*data-manual-screen=\"{screen}\"[^>]*>{label}</button>",
            Markup);
    }

    [Fact]
    public void Modal_exposes_list_stock_editor_CRUD_and_playlist_controls()
    {
        foreach (var id in new[]
                 {
                     "manual-financial-modal",
                     "manual-financial-title",
                     "manual-financial-close",
                     "manual-financial-workspace"
                 })
        {
            Assert.Contains($"id=\"{id}\"", Markup, StringComparison.Ordinal);
        }

        foreach (var intent in new[]
                 {
                     "open-manual-financial",
                     "close-manual-financial",
                     "search-manual-financial",
                     "find-manual-financial",
                     "toggle-manual-financial-name-sort",
                     "load-manual-financial",
                     "begin-manual-financial-create",
                     "search-manual-financial-stocks",
                     "select-manual-financial-stock",
                     "save-manual-financial",
                     "delete-manual-financial",
                     "delete-all-manual-financial",
                     "activate-manual-financial-action"
                 })
        {
            Assert.Contains($"\"{intent}\"", App, StringComparison.Ordinal);
        }

        Assert.Contains(".manual-financial-dialog", Styles, StringComparison.Ordinal);
        Assert.Contains(".manual-financial-grid", Styles, StringComparison.Ordinal);
    }

    [Fact]
    public void GraphE_find_and_name_header_sort_are_generation_bound_native_intents()
    {
        Assert.Contains("manual-financial-find-query", App, StringComparison.Ordinal);
        Assert.Contains("dataset.manualFindDirection", App, StringComparison.Ordinal);
        Assert.Contains("dataset.manualNameSort", App, StringComparison.Ordinal);
        Assert.Contains("dataset.manualGeneration", App, StringComparison.Ordinal);
        Assert.Contains("send(\"find-manual-financial\"", App, StringComparison.Ordinal);
        Assert.Contains(
            "send(\"toggle-manual-financial-name-sort\"",
            App,
            StringComparison.Ordinal);
        Assert.Contains("generation: generation", App, StringComparison.Ordinal);
    }

    [Fact]
    public void GraphE_two_row_toolbar_keeps_find_controls_pointer_accessible()
    {
        Assert.Contains(
            ".manual-financial-workspace { min-height: 0; display: grid; " +
            "grid-template-rows: auto minmax(0, 1fr);",
            Styles,
            StringComparison.Ordinal);
        Assert.DoesNotContain(
            ".manual-financial-workspace { min-height: 0; display: grid; " +
            "grid-template-rows: 38px minmax(0, 1fr);",
            Styles,
            StringComparison.Ordinal);
    }

    [Fact]
    public void GraphE_uses_only_the_four_same_origin_packaged_reference_images()
    {
        foreach (var relativePath in new[]
                 {
                     "./Previews/pie.bmp",
                     "./Previews/Grow.bmp",
                     "./Previews/sell.bmp",
                     "./Previews/profit.bmp"
                 })
        {
            Assert.Contains($"\"{relativePath}\"", App, StringComparison.Ordinal);
        }

        Assert.Contains("manualFinancialReferenceFigure", App, StringComparison.Ordinal);
        Assert.Contains("기존 송출 화면 참고 이미지", App, StringComparison.Ordinal);
        Assert.Contains(".manual-financial-reference img", Styles, StringComparison.Ordinal);
        Assert.DoesNotContain("../Res/", App, StringComparison.OrdinalIgnoreCase);
        Assert.DoesNotContain("legacy-res.mbn.local", App, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void GraphE_list_projects_bounded_read_only_preview_cells_without_native_authority()
    {
        var start = App.IndexOf("function manualFinancialPreviewColumns", StringComparison.Ordinal);
        var end = App.IndexOf("function blankManualRecord", start, StringComparison.Ordinal);
        Assert.True(start >= 0 && end > start);
        var preview = App[start..end];

        Assert.Contains("row.previewValues", preview, StringComparison.Ordinal);
        Assert.Contains("slice(0, count)", preview, StringComparison.Ordinal);
        Assert.Contains(
            "const cell = manualElement(\"span\", \"manual-financial-preview-cell\", value);",
            App,
            StringComparison.Ordinal);
        Assert.DoesNotMatch(
            new Regex("(?:ROWID|ROW_HANDLE|rowVersion|stockCode|resultId)"),
            preview);
        Assert.Contains("manual-financial-preview-columns-", App, StringComparison.Ordinal);
        Assert.Contains("manual-financial-preview-cell", App, StringComparison.Ordinal);
        Assert.Contains(".manual-financial-preview-cell", Styles, StringComparison.Ordinal);
    }

    [Fact]
    public void Explicit_different_stock_selection_resets_only_a_create_mode_draft()
    {
        Assert.Contains("function shouldResetManualStockDraft", App, StringComparison.Ordinal);
        Assert.Contains("stockIsSelected !== true && stockNameReadOnly !== true", App,
            StringComparison.Ordinal);
        Assert.Contains("draft.rawMode !== true", App, StringComparison.Ordinal);

        var start = App.IndexOf(
            "function selectManualFinancialStock",
            StringComparison.Ordinal);
        var end = App.IndexOf(
            "function captureManualDraftForChangedModel",
            start,
            StringComparison.Ordinal);
        Assert.True(start >= 0 && end > start);
        var helper = App[start..end];
        Assert.Contains("rememberManualDraft();", helper, StringComparison.Ordinal);
        Assert.Contains("manualDraft = blankManualRecord(manualDraft.screen);", helper,
            StringComparison.Ordinal);
        Assert.Contains("manualDraftResetPending = true;", helper, StringComparison.Ordinal);
        Assert.Contains("manualDraft = previousDraft;", helper, StringComparison.Ordinal);
    }

    [Fact]
    public void Manual_Web_section_sends_values_and_opaque_ids_without_DB_or_scene_authority()
    {
        var start = App.IndexOf("function blankManualRecord", StringComparison.Ordinal);
        var end = App.IndexOf("function renderDialog", start, StringComparison.Ordinal);
        Assert.True(start >= 0 && end > start);
        var manualSection = App[start..end];

        Assert.DoesNotMatch(
            new Regex("(?:INPUT_PIE|INPUT_GROW|INPUT_SELL|INPUT_PROFIT|s5076|s5079|s5080|s5081|rowVersion|builderKey|cutCode|dataCode|confirmationToken)"),
            manualSection);
        Assert.Contains("dataset.manualResultId", manualSection, StringComparison.Ordinal);
        Assert.Contains("dataset.manualStockResultId", manualSection, StringComparison.Ordinal);
        Assert.Contains("dataset.manualActionId", manualSection, StringComparison.Ordinal);
    }

    [Fact]
    public void MainWindow_composes_real_read_and_one_shot_write_services_and_busy_dispatch()
    {
        Assert.Contains("new LegacyManualFinancialScreenService(", MainWindow, StringComparison.Ordinal);
        Assert.Contains("new OracleManualFinancialMutationExecutor(", MainWindow, StringComparison.Ordinal);
        Assert.Contains("new LegacyStockSearchService(", MainWindow, StringComparison.Ordinal);
        Assert.Contains("manualFinancialWorkflow: new LegacyManualFinancialWorkflow(", MainWindow, StringComparison.Ordinal);
        Assert.Contains("LegacySaveManualFinancialIntent", MainWindow, StringComparison.Ordinal);
        Assert.Contains("LegacyDeleteManualFinancialIntent", MainWindow, StringComparison.Ordinal);
        Assert.Contains("LegacyDeleteAllManualFinancialIntent", MainWindow, StringComparison.Ordinal);
        Assert.Contains("_intentGate.WaitAsync(", MainWindow, StringComparison.Ordinal);
        Assert.Matches(
            new Regex(@"_intentGate\.WaitAsync\(\s*0,\s*_lifetimeCancellation\.Token\)"),
            MainWindow);
        Assert.DoesNotContain("SaveManualFinancialAsync(", MainWindow[..MainWindow.IndexOf(
            "HandleIntentAsync",
            StringComparison.Ordinal)], 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.");
    }
}
