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

namespace MBN_STOCK_WEBVIEW.LegacyBridge.Tests;

public sealed class LegacyManualListsBridgeTests
{
    [Fact]
    public void OriginalOkActionHasOneClosedEmptyPayloadIntent()
    {
        Assert.True(LegacyBridgeProtocol.TryParseIntent(
            "{\"type\":\"confirm-manual-list\",\"payload\":{}}",
            out var intent,
            out _));
        Assert.IsType<LegacyConfirmManualListIntent>(intent);

        Assert.False(LegacyBridgeProtocol.TryParseIntent(
            "{\"type\":\"confirm-manual-list\",\"payload\":{\"retry\":true}}",
            out _,
            out _));
    }

    [Theory]
    [InlineData("individual", LegacyManualListScreen.NetSell, S5025ManualAudience.Individual)]
    [InlineData("foreign", LegacyManualListScreen.NetSell, S5025ManualAudience.Foreign)]
    [InlineData("institution", LegacyManualListScreen.NetSell, S5025ManualAudience.Institution)]
    [InlineData("vi", LegacyManualListScreen.Vi, S5025ManualAudience.Individual)]
    public void Open_accepts_only_closed_screen_identifiers(
        string screen,
        LegacyManualListScreen expectedScreen,
        S5025ManualAudience expectedAudience)
    {
        var json = JsonSerializer.Serialize(new
        {
            type = "open-manual-list",
            payload = new { screen }
        });

        Assert.True(LegacyBridgeProtocol.TryParseIntent(json, out var intent, out _));
        var opened = Assert.IsType<LegacyOpenManualListIntent>(intent);
        Assert.Equal(expectedScreen, opened.Screen);
        Assert.Equal(expectedAudience, opened.Audience);
        Assert.False(LegacyBridgeProtocol.TryParseIntent(
            "{\"type\":\"open-manual-list\",\"payload\":{\"screen\":\"vi\",\"path\":\"C:\\\\Data\"}}",
            out _,
            out _));
    }

    [Fact]
    public void Net_cell_accepts_one_opaque_row_and_safe_value_only()
    {
        Assert.True(LegacyBridgeProtocol.TryParseIntent(
            "{\"type\":\"set-manual-net-sell-cell\",\"payload\":{\"rowId\":\"manual-net-row-1\",\"field\":\"leftAmount\",\"value\":\"1,000\"}}",
            out var intent,
            out _));
        var cell = Assert.IsType<LegacySetManualNetSellCellIntent>(intent);
        Assert.Equal(LegacyManualNetSellField.LeftAmount, cell.Field);

        foreach (var invalid in new[]
                 {
                     "{\"rowId\":\"manual-net-row-1\",\"field\":\"leftAmount\",\"value\":\"bad^value\"}",
                     "{\"rowId\":\"manual-net-row-1\",\"field\":\"leftAmount\",\"value\":\"1\",\"audience\":\"FOREIGN\"}",
                     "{\"rowId\":\"manual-net-row-1\",\"field\":\"code\",\"value\":\"005930\"}"
                 })
        {
            Assert.False(LegacyBridgeProtocol.TryParseIntent(
                $"{{\"type\":\"set-manual-net-sell-cell\",\"payload\":{invalid}}}",
                out _,
                out _));
        }
    }

    [Fact]
    public void VI_mutations_accept_opaque_ids_and_never_codes_items_or_versions()
    {
        Assert.True(Parse("select-manual-vi-result", "{\"resultId\":\"manual-vi-result-0001\"}"));
        Assert.True(Parse("add-manual-vi-result", "{\"resultId\":\"manual-vi-result-0001\"}"));
        Assert.True(Parse("move-manual-vi-item", "{\"itemId\":\"manual-vi-item-0001\",\"direction\":\"up\"}"));
        Assert.True(Parse("delete-manual-vi-item", "{\"itemId\":\"manual-vi-item-0001\"}"));
        Assert.True(Parse("save-manual-vi", "{}"));
        Assert.False(Parse("save-manual-vi", "{\"version\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}"));
        Assert.False(Parse("add-manual-vi-result", "{\"code\":\"005930\",\"name\":\"삼성전자\"}"));
    }

    [Fact]
    public void VI_search_accepts_the_original_blank_full_list_request()
    {
        Assert.True(LegacyBridgeProtocol.TryParseIntent(
            "{\"type\":\"search-manual-vi\",\"payload\":{\"query\":\"\"}}",
            out var intent,
            out _));
        Assert.Equal(string.Empty, Assert.IsType<LegacySearchManualViIntent>(intent).Query);
    }

    [Fact]
    public void State_projects_display_rows_but_not_native_codes_versions_or_paths()
    {
        var viItems = Enumerable.Range(1, 9)
            .Select(index => new LegacyManualViItemView(
                $"manual-vi-item-{index}",
                index,
                $"VI종목{index}"))
            .ToArray();
        var manual = new LegacyManualListsSnapshot(
            true,
            LegacyManualListScreen.Vi,
            S5025ManualAudience.Individual,
            true,
            "READY",
            null,
            false,
            Array.Empty<LegacyManualNetSellRowView>(),
            false,
            viItems,
            2,
            true,
            "삼성",
            [new LegacyManualViSearchResultView(
                "manual-vi-result-1",
                "삼성전자",
                "코스피")],
            "조회 완료",
            LegacyOperatorStatusKind.Information,
            true,
            true)
        {
            SelectedSearchResultId = "manual-vi-result-1",
            SearchIsTruncated = true
        };
        var snapshot = new LegacyOperatorSnapshot(
            1,
            string.Empty,
            Array.Empty<LegacyStockResultRow>(),
            null,
            Array.Empty<LegacyCutViewRow>(),
            Array.Empty<LegacyOperatorPlaylistRow>(),
            null,
            string.Empty,
            LegacyOperatorStatusKind.Neutral,
            ManualLists: manual);

        var json = LegacyBridgeProtocol.SerializeState(snapshot);
        using var document = JsonDocument.Parse(json);
        var projected = document.RootElement.GetProperty("payload").GetProperty("manualLists");
        Assert.Equal(
            "manual-vi-result-1",
            projected.GetProperty("selectedSearchResultId").GetString());
        Assert.True(projected.GetProperty("searchIsTruncated").GetBoolean());

        Assert.True(projected.GetProperty("isOpen").GetBoolean());
        Assert.Equal(9, projected.GetProperty("viItems").GetArrayLength());
        Assert.Equal("VI종목1", projected.GetProperty("viItems")[0].GetProperty("name").GetString());
        Assert.Equal(2, projected.GetProperty("viPageCount").GetInt32());
        Assert.True(projected.GetProperty("viItemsAreFresh").GetBoolean());
        Assert.True(projected.GetProperty("canSave").GetBoolean());
        Assert.True(projected.GetProperty("canMaterializePlaylist").GetBoolean());
        Assert.False(projected.TryGetProperty("rowVersion", out _));
        Assert.DoesNotContain("005930", projected.GetRawText(), StringComparison.Ordinal);
        Assert.DoesNotContain("path", projected.GetRawText(), StringComparison.OrdinalIgnoreCase);
        Assert.DoesNotContain("version", projected.GetRawText(), StringComparison.OrdinalIgnoreCase);
    }

    private static bool Parse(string type, string payload) =>
        LegacyBridgeProtocol.TryParseIntent(
            $"{{\"type\":\"{type}\",\"payload\":{payload}}}",
            out _,
            out _);
}
