using System.Text;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;
using MMoneyCoderSharp.Data;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class LegacyManualOperatorDataCodecTests
{
    [Fact]
    public void NetSell_requires_five_rows_and_the_original_empty_terminal_record()
    {
        var expected = Rows();
        var canonical = LegacyManualOperatorDataCodec.SerializeNetSell(expected);

        Assert.Equal(expected, LegacyManualOperatorDataCodec.ParseNetSell(canonical));
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.ParseNetSell(canonical.AsSpan(0, canonical.Length - 2)));
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.SerializeNetSell(expected.Take(4).ToArray()));
    }

    [Fact]
    public void NetSell_rejects_unicode_bom_delimiters_and_non_cp949_text()
    {
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.ParseNetSell(
                Encoding.UTF8.GetBytes("a^b^c^d\r\n")));

        var delimiter = Rows().ToArray();
        delimiter[0] = delimiter[0] with { LeftName = "bad^name" };
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.SerializeNetSell(delimiter));

        var emoji = Rows().ToArray();
        emoji[0] = emoji[0] with { LeftName = "😀" };
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.SerializeNetSell(emoji));
    }

    [Fact]
    public void Vi_preserves_original_order_and_duplicates_in_nine_columns()
    {
        LegacyManualViItem[] expected =
        [
            new("PKR7005930003", "삼성전자"),
            new("PKR7016360000", "삼성증권"),
            new("PKR7005930003", "삼성전자")
        ];

        var bytes = LegacyManualOperatorDataCodec.SerializeVi(expected);
        var actual = LegacyManualOperatorDataCodec.ParseVi(bytes);

        Assert.Equal(expected, actual);
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        Assert.All(
            Encoding.GetEncoding(949).GetString(bytes)
                .Split("\r\n", StringSplitOptions.RemoveEmptyEntries),
            row => Assert.Equal(9, row.Split('^').Length));
    }

    [Fact]
    public void Vi_enforces_twenty_pages_and_the_4000_byte_serialized_bound()
    {
        var tooMany = Enumerable.Range(1, 101)
            .Select(index => new LegacyManualViItem(index.ToString("D6"), $"종목{index}"))
            .ToArray();
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.SerializeVi(tooMany));

        var tooLarge = Enumerable.Range(1, 100)
            .Select(index => new LegacyManualViItem(
                $"CODE{index:D3}" + new string('X', 30),
                $"종목{index:D3}" + new string('가', 30)))
            .ToArray();
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.SerializeVi(tooLarge));
    }

    [Fact]
    public void Vi_accepts_an_existing_empty_file_but_rejects_nonempty_extra_columns()
    {
        Assert.Empty(LegacyManualOperatorDataCodec.ParseVi(Array.Empty<byte>()));
        Assert.Throws<LegacyManualOperatorDataValidationException>(() =>
            LegacyManualOperatorDataCodec.ParseVi(
                Cp949("005930^삼성전자^unexpected^^^^^^\r\n")));
    }

    private static IReadOnlyList<S5025TrustedManualRow> Rows() =>
    [
        new("삼성전자", "1,000", "SK하이닉스", "-2,000"),
        new("현대차", "2", "기아", "-2"),
        new("NAVER", "3", "카카오", "-3"),
        new("LG화학", "4", "포스코", "-4"),
        new("한화", "5", "셀트리온", "-5")
    ];

    private static byte[] Cp949(string value)
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        return Encoding.GetEncoding(949).GetBytes(value);
    }
}
