namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

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

    [Fact]
    public void StockSearchFeedbackStaysConciseAndUsesNativeState()
    {
        var feedback = Slice(
            App,
            "function renderStockSearchMeta(state)",
            "function pointerPosition(event)");

        Assert.Contains("state.isBusy === true", feedback, StringComparison.Ordinal);
        Assert.Contains("label = \"검색 중\"", feedback, StringComparison.Ordinal);
        Assert.Contains("String(results.length) + \"건\"", feedback,
            StringComparison.Ordinal);
        Assert.Contains("row.index === state.selectedStockIndex", feedback,
            StringComparison.Ordinal);
        Assert.Contains("selected.displayName", feedback, StringComparison.Ordinal);
        Assert.Contains("stockSearchMeta.hidden = label.length === 0", feedback,
            StringComparison.Ordinal);
        Assert.Contains("stockResults.dataset.emptyLabel = \"결과 없음\"", feedback,
            StringComparison.Ordinal);
        Assert.Contains("delete stockResults.dataset.emptyLabel", feedback,
            StringComparison.Ordinal);
    }

    [Fact]
    public void EmptyCutFeedbackDistinguishesStockSelectionAndClearsWhenRowsReturn()
    {
        var cuts = Slice(App, "function renderCuts(state)", "cutList.addEventListener");

        Assert.Contains("state.cutRows.length === 0", cuts, StringComparison.Ordinal);
        Assert.Contains("Number.isInteger(state.selectedStockIndex)", cuts,
            StringComparison.Ordinal);
        Assert.Contains("? \"컷 없음\"", cuts, StringComparison.Ordinal);
        Assert.Contains(": \"종목을 선택하세요\"", cuts, StringComparison.Ordinal);
        Assert.Contains("delete cutList.dataset.emptyLabel", cuts,
            StringComparison.Ordinal);
    }

    [Fact]
    public void GlobalBusyFeedbackDoesNotMislabelEveryOperationAsSearch()
    {
        var render = Slice(App, "function render(state)",
            "Object.keys(operatorFolderControls)");

        Assert.Contains("document.body.classList.toggle(\"busy\", isBusy)", render,
            StringComparison.Ordinal);
        Assert.Contains("document.body.setAttribute(\"aria-busy\"", render,
            StringComparison.Ordinal);
        Assert.Contains("renderStockResults(state);\n    renderStockSearchMeta(state);", render,
            StringComparison.Ordinal);
        Assert.Contains("isBusy ? \"처리 중\"", render, StringComparison.Ordinal);
        Assert.DoesNotContain("종목을 검색하고 있습니다.", render, StringComparison.Ordinal);
    }

    private static string Slice(string source, string startMarker, string endMarker)
    {
        var start = source.IndexOf(startMarker, StringComparison.Ordinal);
        Assert.True(start >= 0, $"Missing start marker: {startMarker}");
        var end = source.IndexOf(endMarker, start, StringComparison.Ordinal);
        Assert.True(end > start, $"Missing end marker: {endMarker}");
        return source[start..end];
    }

    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 could not be located.");
    }
}
