using System.Text.Json;
using MBN_STOCK_WEBVIEW.Core.Playout;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class TrustedViManualReferenceTests
{
    private const string Version =
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    [Fact]
    public async Task Realistic_twenty_page_web_reference_crosses_bridge_and_resolves_native_names()
    {
        var names = Enumerable.Range(1, 100)
            .Select(index => $"현실적인긴종목명테스트{index}")
            .ToArray();
        using var document = JsonDocument.Parse($$"""
            {
              "requestId": "vi_prepare_20_pages",
              "command": "prepare",
              "playlist": [
                {
                  "id": "vi_entry_20_pages",
                  "code": "5074",
                  "enabled": true,
                  "fadeDuration": 4,
                  "selection": {
                    "groupCode": "PAGED_VI",
                    "subject": "{{TrustedViManualReference.SubjectSentinel}}",
                    "graphicType": "INPUT_ORDER",
                    "subtype": "CURRENT",
                    "dataCode": "{{Version}}"
                  }
                }
              ],
              "selectedIndex": 0
            }
            """);

        var parsed = PlayoutBridgeProtocol.ParseWorkflowCommand(document.RootElement);

        Assert.True(parsed.IsValid, parsed.Error);
        var selection = Assert.Single(parsed.Request.Playlist!).Selection!;
        var request = await TrustedViManualReference.ResolveAsync(
            selection,
            pageIndexZeroBased: 19,
            new StubSnapshotSource(names, Version));
        Assert.Equal(20, request.PageNumberOneBased);
        Assert.Equal(names, request.StockNames);
    }

    [Fact]
    public async Task Version_mismatch_fails_closed_before_query_request_creation()
    {
        var selection = TrustedSelection(Version);

        await Assert.ThrowsAsync<LegacySceneDataException>(() =>
            TrustedViManualReference.ResolveAsync(
                selection,
                0,
                new StubSnapshotSource(["삼성전자"], new string('b', 64))));
    }

    [Fact]
    public async Task Modified_sentinel_cannot_downgrade_a_versioned_reference()
    {
        var selection = TrustedSelection(Version) with
        {
            Subject = "@MBN_VI_SNAPSHOT_V0"
        };

        await Assert.ThrowsAsync<LegacySceneDataException>(() =>
            TrustedViManualReference.ResolveAsync(
                selection,
                0,
                new StubSnapshotSource(["삼성전자"], Version)));
    }

    [Fact]
    public async Task Historical_bounded_name_list_remains_compatible()
    {
        var selection = new LegacySceneSelection(
            "PAGED_VI",
            "삼성전자,SK하이닉스,삼성전자",
            "INPUT_ORDER",
            "CURRENT",
            string.Empty);

        var request = await TrustedViManualReference.ResolveAsync(
            selection,
            1,
            trustedSource: null);

        Assert.Equal(2, request.PageNumberOneBased);
        Assert.Equal(["삼성전자", "SK하이닉스", "삼성전자"], request.StockNames);
    }

    private static LegacySceneSelection TrustedSelection(string version) => new(
        "PAGED_VI",
        TrustedViManualReference.SubjectSentinel,
        "INPUT_ORDER",
        "CURRENT",
        version);

    private sealed class StubSnapshotSource(
        IReadOnlyList<string> names,
        string version) : ITrustedViStockNameSnapshotSource
    {
        public Task<TrustedViStockNameSnapshot> ReadStockNameSnapshotAsync(
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            return Task.FromResult(new TrustedViStockNameSnapshot(names, version));
        }
    }
}
