using System.Globalization;
using System.Text.Json;
using MBN_STOCK_WEBVIEW.LegacyApplication;
using MMoneyCoderSharp.Data;

namespace MBN_STOCK_WEBVIEW.LegacyBridge.Tests;

public sealed class LegacyThemeBridgeTests
{
    [Fact]
    public async Task ProjectionPreservesFiveThousandRowsAndExplicitTruncationWarningState()
    {
        var workflow = new LegacyThemeWorkflow(new TruncatedThemeService());
        var theme = await workflow.SearchAsync(
            workflow.CreateInitial(),
            string.Empty,
            ThemeSession.PreMarket);
        var snapshot = new LegacyOperatorSnapshot(
            1,
            string.Empty,
            [],
            null,
            [],
            [],
            null,
            "테마 검색 결과가 최대 5,000건으로 제한되었습니다.",
            LegacyOperatorStatusKind.Warning,
            Theme: theme);

        using var document = JsonDocument.Parse(
            LegacyBridgeProtocol.SerializeState(snapshot));
        var payload = document.RootElement.GetProperty("payload");
        var projected = payload.GetProperty("theme");

        Assert.True(projected.GetProperty("searchIsTruncated").GetBoolean());
        Assert.Equal(5_000, projected.GetProperty("searchResults").GetArrayLength());
        Assert.Equal("warning", payload.GetProperty("statusKind").GetString());
        Assert.Contains("5,000", payload.GetProperty("statusMessage").GetString());
        Assert.DoesNotContain("themeCode", projected.GetRawText(), StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public async Task ProjectionPreservesRawLegacyTitlesExplicitMarketAndEmptyPreviewGuards()
    {
        var workflow = new LegacyThemeWorkflow(new CompatibilityThemeService());
        var search = await workflow.SearchAsync(
            workflow.CreateInitial(),
            string.Empty,
            ThemeSession.PreMarket);
        var theme = await workflow.SelectAsync(search, "theme-result-005");
        var snapshot = new LegacyOperatorSnapshot(
            1,
            string.Empty,
            [],
            null,
            [],
            [],
            null,
            "Theme compatibility",
            LegacyOperatorStatusKind.Information,
            Theme: theme);

        using var document = JsonDocument.Parse(
            LegacyBridgeProtocol.SerializeState(snapshot));
        var projected = document.RootElement.GetProperty("payload").GetProperty("theme");
        var rows = projected.GetProperty("searchResults").EnumerateArray().ToArray();

        Assert.Equal(5, rows.Length);
        Assert.Equal(" Legacy ", rows[0].GetProperty("displayTitle").GetString());
        Assert.Equal("Same", rows[1].GetProperty("displayTitle").GetString());
        Assert.Equal("Same", rows[2].GetProperty("displayTitle").GetString());
        Assert.Equal("Desk(NXT)", rows[3].GetProperty("displayTitle").GetString());
        Assert.Equal("krx", rows[3].GetProperty("market").GetString());
        Assert.Equal(" Empty NXT(NXT)", rows[4].GetProperty("displayTitle").GetString());
        Assert.Equal("nxt", rows[4].GetProperty("market").GetString());
        Assert.Equal(0, projected.GetProperty("previewItems").GetArrayLength());
        Assert.All(projected.GetProperty("actions").EnumerateArray(), action =>
        {
            Assert.False(action.GetProperty("isAvailable").GetBoolean());
            Assert.Equal(
                "theme-preview-is-empty",
                action.GetProperty("unavailableReason").GetString());
        });
        Assert.DoesNotContain("themeCode", projected.GetRawText(), StringComparison.OrdinalIgnoreCase);
    }

    private sealed class TruncatedThemeService : IThemeSelectionService
    {
        public Task<ThemeSearchResult> SearchAsync(
            string query,
            ThemeSession nxtSession,
            int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults,
            CancellationToken cancellationToken = default)
        {
            Assert.Equal(LegacyThemeWorkflow.MaximumSearchResults, maximumResults);
            var rows = Enumerable.Range(0, maximumResults)
                .Select(index => new ThemeSelectorItem(
                    new ThemeSelectionIdentity(
                        ThemeMarket.Krx,
                        ThemeSession.NotApplicable,
                        index.ToString("D8", CultureInfo.InvariantCulture),
                        $"Theme {index}"),
                    DataSourceKind.Oracle))
                .ToArray();
            return Task.FromResult(new ThemeSearchResult(
                query,
                nxtSession,
                DateTimeOffset.UtcNow,
                rows,
                IsTruncated: true));
        }

        public Task<ThemePreviewResult> PreviewAsync(
            ThemeSelectionIdentity identity,
            int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems,
            CancellationToken cancellationToken = default) =>
            Task.FromResult(new ThemePreviewResult(
                identity,
                DateTimeOffset.UtcNow,
                [],
                IsTruncated: false));
    }

    private sealed class CompatibilityThemeService : IThemeSelectionService
    {
        public Task<ThemeSearchResult> SearchAsync(
            string query,
            ThemeSession nxtSession,
            int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults,
            CancellationToken cancellationToken = default) =>
            Task.FromResult(new ThemeSearchResult(
                query,
                nxtSession,
                DateTimeOffset.UtcNow,
                [
                    Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000001", " Legacy "),
                    Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000002", "Same"),
                    Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000003", "Same"),
                    Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000004", "Desk(NXT)"),
                    Item(ThemeMarket.Nxt, nxtSession, "00000005", " Empty NXT")
                ],
                IsTruncated: false));

        public Task<ThemePreviewResult> PreviewAsync(
            ThemeSelectionIdentity identity,
            int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems,
            CancellationToken cancellationToken = default) =>
            Task.FromResult(new ThemePreviewResult(
                identity,
                DateTimeOffset.UtcNow,
                [],
                IsTruncated: false));

        private static ThemeSelectorItem Item(
            ThemeMarket market,
            ThemeSession session,
            string code,
            string title) =>
            new(
                new ThemeSelectionIdentity(market, session, code, title),
                market == ThemeMarket.Krx ? DataSourceKind.Oracle : DataSourceKind.MariaDb);
    }
}
