using System.Globalization;
using MBN_STOCK_WEBVIEW.Core.Playout;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class FoundationalSceneBuildersTests
{
    [Fact]
    public void S5076_matches_legacy_value_visibility_and_circle_order()
    {
        var data = new S5076SceneData(
            "테스트",
            "2026.07",
            [
                new RevenueSliceData("국내", "25.0", 25),
                new RevenueSliceData("해외", "75.0", 75),
                null,
                null,
                null
            ]);

        var actual = new S5076SceneMutationBuilder().Build(data).Select(Describe).ToArray();

        Assert.Equal(
        [
            "V:title=테스트 주요매출 구성",
            "V:date=2026.07 기준",
            "S:circle1=0", "S:group1=0",
            "S:circle2=0", "S:group2=0",
            "S:circle3=0", "S:group3=0",
            "S:circle4=0", "S:group4=0",
            "S:circle5=0", "S:group5=0",
            "S:circle1=1", "S:group1=1",
            "V:word1=국내", "V:percent1=25.0",
            "A:circle1:0:0:0:3", "A:circle1:1:0:90:3",
            "S:circle2=1", "S:group2=1",
            "V:word2=해외", "V:percent2=75.0",
            "A:circle2:0:90:90:3", "A:circle2:1:90:360:3"
        ], actual);
    }

    [Fact]
    public void S5081_matches_legacy_mixed_profit_sequence_and_scaling()
    {
        var data = new S5081SceneData(
            "A사",
            [
                new("1Q", 100), new("2Q", -50), new("3Q", 25),
                new("4Q", 0), new("5Q", 50), new("6Q", -25)
            ]);

        var actual = new S5081SceneMutationBuilder().Build(data).Select(Describe).ToArray();

        Assert.Equal(
        [
            "V:title=A사 영업이익",
            "V:quarter1=1Q", "V:quarter2=2Q", "V:quarter3=3Q",
            "V:quarter4=4Q", "V:quarter5=5Q", "V:quarter6=6Q",
            "S:barG1_1=0", "S:barG1_2=0", "S:barG1_1=1", "V:value1_1=100",
            "S:barG2_1=0", "S:barG2_2=0", "S:barG2_2=1", "V:value2_2=-50",
            "S:barG3_1=0", "S:barG3_2=0", "S:barG3_1=1", "V:value3_1=25",
            "S:barG4_1=0", "S:barG4_2=0", "S:barG4_1=1", "V:value4_1=0",
            "S:barG5_1=0", "S:barG5_2=0", "S:barG5_1=1", "V:value5_1=50",
            "S:barG6_1=0", "S:barG6_2=0", "S:barG6_2=1", "V:value6_2=-25",
            "K:centerbar:0:0:-131.66667:0:2",
            "Z:bar1_1:0:1.2:0:2", "Z:bar2_2:0:0.6:0:2",
            "Z:bar3_1:0:0.3:0:2", "Z:bar4_1:0:0:0:2",
            "Z:bar5_1:0:0.6:0:2", "Z:bar6_2:0:0.3:0:2"
        ], actual);
    }

    [Fact]
    public void S5081_all_zero_data_is_finite_and_does_not_repeat_a_failed_sdk_call()
    {
        var data = new S5081SceneData(
            "A사",
            Enumerable.Range(1, 6).Select(index => new QuarterlyProfitData($"{index}Q", 0)).ToArray());

        var actual = new S5081SceneMutationBuilder().Build(data);

        Assert.DoesNotContain(actual.Select(Describe), value => value.Contains("NaN", StringComparison.Ordinal));
        Assert.Equal("K:centerbar:0:0:-250:0:2", Describe(actual[31]));
        Assert.All(actual.Skip(32), mutation => Assert.Contains(":0:0:2", Describe(mutation)));
    }

    [Fact]
    public void S5085_maps_typed_metrics_to_the_original_objects_and_colors()
    {
        var actual = new S5085SceneMutationBuilder().Build(new S5085SceneData(
        [
            new(ProgramTradingMetric.NetBuy, 1234.5),
            new(ProgramTradingMetric.Basis, -2.25),
            new(ProgramTradingMetric.Futures, 0)
        ])).Select(Describe);

        Assert.Equal(
        [
            "V:title1=순매수", "C:price1:171:0:0:255", "V:price1=1,234.5",
            "V:title4=베이시스", "C:price4:15:99:188:255", "V:price4=-2.25",
            "V:title6=선물", "C:price6:47:47:47:255", "V:price6=0"
        ], actual);
    }

    [Fact]
    public void S6067_matches_legacy_market_and_institution_slot_mapping()
    {
        var actual = new S6067SceneMutationBuilder().Build(new S6067SceneData(
        [
            new(InstitutionMarket.Kospi, InstitutionKind.Securities, 1000),
            new(InstitutionMarket.Kosdaq, InstitutionKind.Fund, -327),
            new(InstitutionMarket.Other, InstitutionKind.Bank, 0)
        ])).Select(Describe);

        Assert.Equal(
        [
            "C:row1_value1:171:0:0:255", "V:row1_value1=1,000",
            "C:row2_value5:15:99:188:255", "V:row2_value5=-327",
            "C:row3_value4:47:47:47:255", "V:row3_value4=0"
        ], actual);
    }

    [Fact]
    public void S8067_matches_legacy_world_map_order_including_flat_background_target()
    {
        var actual = new S8067SceneMutationBuilder().Build(new S8067SceneData(
        [
            new(WorldMarket.Korea, 2765.1234, 12.5, 1.23, SceneMarketTrend.Up),
            new(WorldMarket.Nasdaq, 18000, -0.0, -0.0, SceneMarketTrend.Down)
        ])).Select(Describe);

        Assert.Equal(
        [
            "V:price_한국=2,765.123", "V:rate_한국=1.23",
            "S:up_한국=0", "S:down_한국=0", "S:flat_한국=0",
            "C:bg_한국:170:0:0:255", "S:up_한국=1",
            "V:price_나스닥=18,000", "V:rate_나스닥=-0.00",
            "S:up_나스닥=0", "S:down_나스닥=0", "S:flat_나스닥=0",
            "C:bg:191:191:191:255", "S:flat_나스닥=1"
        ], actual);
    }

    [Fact]
    public void S8086_matches_legacy_quote_values_and_color_order()
    {
        var actual = new S8086SceneMutationBuilder().Build(new S8086SceneData(
            "WTI 유가",
            CommodityUnit.DollarsPerBarrel,
            78.2,
            -1.1,
            -1.39,
            SceneMarketTrend.Down)).Select(Describe);

        Assert.Equal(
        [
            "V:unit=단위: 달러/배럴", "V:title=WTI 유가",
            "V:price=78.20", "V:changePrice=-1.10", "V:rate=-1.39",
            "C:bg:14:100:188:255", "C:changePrice:14:100:188:255",
            "C:rate:14:100:188:255"
        ], actual);
    }

    private static string Describe(PlayoutMutation mutation) => mutation switch
    {
        PlayoutSetValue value => $"V:{value.ObjectName}={value.Value}",
        PlayoutSetVisible visible => $"S:{visible.ObjectName}={(visible.IsVisible ? 1 : 0)}",
        PlayoutSetFaceColor color => $"C:{color.ObjectName}:{color.Red}:{color.Green}:{color.Blue}:{color.Alpha}",
        PlayoutSetPositionKey key => FormattableString.Invariant(
            $"K:{key.ObjectName}:{key.KeyIndex}:{key.X}:{key.Y}:{key.Z}:{(int)key.Components}"),
        PlayoutSetScale scale => FormattableString.Invariant(
            $"Z:{scale.ObjectName}:{scale.X}:{scale.Y}:{scale.Z}:{(int)scale.Components}"),
        PlayoutSetCircleAngleKey angle => FormattableString.Invariant(
            $"A:{angle.ObjectName}:{angle.KeyIndex}:{angle.Start}:{angle.End}:{(int)angle.Components}"),
        _ => mutation.GetType().Name
    };
}
