using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class ChartLegacySceneRequestResolverTests
{
    private readonly ChartLegacySceneRequestResolver _resolver = new();

    [Theory]
    [InlineData("해외지수", "다우", "미국업종", SectorIndexMarket.Dow)]
    [InlineData("해외지수", "나스닥", "미국업종", SectorIndexMarket.Nasdaq)]
    [InlineData("해외지수", "S&P", "미국업종", SectorIndexMarket.StandardAndPoor)]
    [InlineData("업종_코스피", "코스피", "섹터지수", SectorIndexMarket.Kospi)]
    [InlineData("업종_코스닥", "코스닥", "섹터지수", SectorIndexMarket.Kosdaq)]
    public void S5078_maps_all_original_subject_branches(
        string group,
        string subject,
        string graphic,
        SectorIndexMarket expected)
    {
        var request = _resolver.CreateS5078Request(
            Entry("5078", group, subject, graphic));

        Assert.Equal(expected, request.Market);
    }

    [Theory]
    [InlineData("FOREIGN_INDEX", "DOW", "US_SECTOR_INDEX", SectorIndexMarket.Dow)]
    [InlineData("FOREIGN_INDEX", "NASDAQ", "US_SECTOR_INDEX", SectorIndexMarket.Nasdaq)]
    [InlineData("FOREIGN_INDEX", "S&P500", "US_SECTOR_INDEX", SectorIndexMarket.StandardAndPoor)]
    [InlineData("INDUSTRY_KOSPI", "KOSPI", "SECTOR_INDEX", SectorIndexMarket.Kospi)]
    [InlineData("INDUSTRY_KOSDAQ", "KOSDAQ", "SECTOR_INDEX", SectorIndexMarket.Kosdaq)]
    public void S5078_accepts_only_the_explicit_canonical_aliases(
        string group,
        string subject,
        string graphic,
        SectorIndexMarket expected)
    {
        Assert.Equal(
            expected,
            _resolver.CreateS5078Request(
                Entry("5078", group, subject, graphic)).Market);
    }

    [Fact]
    public void S5079_and_S5080_preserve_the_original_jongmok_stock_name()
    {
        var growth = _resolver.CreateS5079Request(Entry(
            "5079",
            "코스피",
            "삼성전자",
            "성장성 지표",
            dataCode: "005930"));
        var sales = _resolver.CreateS5080Request(Entry(
            "5080",
            "코스닥",
            "셀트리온헬스케어",
            "매출액"));

        Assert.Equal("삼성전자", growth.StockName);
        Assert.Equal("셀트리온헬스케어", sales.StockName);
    }

    [Theory]
    [InlineData("전체", "지수", "개인 매매동향", "라인그래프", InvestorFlowParticipant.Individual)]
    [InlineData("전체", "지수", "기관 매매동향", "라인그래프", InvestorFlowParticipant.Institution)]
    [InlineData("전체", "지수", "외국인 매매동향", "라인그래프", InvestorFlowParticipant.Foreign)]
    [InlineData("ALL", "INDEX", "INDIVIDUAL_TRADING_TREND", "LINE_GRAPH", InvestorFlowParticipant.Individual)]
    [InlineData("ALL", "INDEX", "INSTITUTION_TRADING_TREND", "LINE_GRAPH", InvestorFlowParticipant.Institution)]
    [InlineData("ALL", "INDEX", "FOREIGN_TRADING_TREND", "LINE_GRAPH", InvestorFlowParticipant.Foreign)]
    public void S5083_maps_the_three_forCutInfo_branches(
        string group,
        string subject,
        string graphic,
        string subtype,
        InvestorFlowParticipant expected)
    {
        var request = _resolver.CreateS5083Request(
            Entry("5083", group, subject, graphic, subtype));

        Assert.Equal(expected, request.Participant);
    }

    [Theory]
    [InlineData("코스피", "지수", "코스피 매매동향", "라인그래프", InvestorFlowIndex.Kospi)]
    [InlineData("코스닥", "지수", "코스닥 매매동향", "라인그래프", InvestorFlowIndex.Kosdaq)]
    [InlineData("KOSPI", "INDEX", "KOSPI_TRADING_TREND", "LINE_GRAPH", InvestorFlowIndex.Kospi)]
    [InlineData("KOSDAQ", "INDEX", "KOSDAQ_TRADING_TREND", "LINE_GRAPH", InvestorFlowIndex.Kosdaq)]
    public void S5084_maps_the_two_forCutInfo_branches_and_checks_code_consistency(
        string group,
        string subject,
        string graphic,
        string subtype,
        InvestorFlowIndex expected)
    {
        var request = _resolver.CreateS5084Request(
            Entry("5084", group, subject, graphic, subtype));

        Assert.Equal(expected, request.Index);
    }

    [Fact]
    public void Resolve_returns_a_closed_wrapper_for_every_supported_cut()
    {
        Assert.Equal("s5078", _resolver.Resolve(
            Entry("5078", "해외지수", "다우", "미국업종")).BuilderKey);
        Assert.Equal("s5079", _resolver.Resolve(
            Entry("5079", "코스피", "A", "성장성 지표")).BuilderKey);
        Assert.Equal("s5080", _resolver.Resolve(
            Entry("5080", "코스닥", "B", "매출액")).BuilderKey);
        Assert.Equal("s5083", _resolver.Resolve(
            Entry("5083", "전체", "지수", "개인 매매동향", "라인그래프")).BuilderKey);
        Assert.Equal("s5084", _resolver.Resolve(
            Entry("5084", "코스피", "지수", "코스피 매매동향", "라인그래프")).BuilderKey);

        Assert.IsType<LegacyS5078ChartLoadRequest>(_resolver.Resolve(
            Entry("5078", "해외지수", "다우", "미국업종")));
        Assert.IsType<LegacyS5079ChartLoadRequest>(_resolver.Resolve(
            Entry("5079", "코스피", "A", "성장성 지표")));
        Assert.IsType<LegacyS5080ChartLoadRequest>(_resolver.Resolve(
            Entry("5080", "코스닥", "B", "매출액")));
        Assert.IsType<LegacyS5083ChartLoadRequest>(_resolver.Resolve(
            Entry("5083", "전체", "지수", "기관 매매동향", "라인그래프")));
        Assert.IsType<LegacyS5084ChartLoadRequest>(_resolver.Resolve(
            Entry("5084", "코스닥", "지수", "코스닥 매매동향", "라인그래프")));
    }

    [Theory]
    [InlineData("업종_코스피", "다우", "섹터지수", "", "")]
    [InlineData("해외지수", "코스피", "미국업종", "", "")]
    [InlineData("해외지수", "DOW JONES", "미국업종", "", "")]
    [InlineData("해외지수", "다우", "미국업종", "EXTRA", "")]
    [InlineData("해외지수", "다우", "미국업종", "", "005930")]
    public void S5078_rejects_cross_branch_and_open_ended_selectors(
        string group,
        string subject,
        string graphic,
        string subtype,
        string dataCode)
    {
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5078Request(
                Entry("5078", group, subject, graphic, subtype, dataCode)));
    }

    [Theory]
    [InlineData("전체", "A", "성장성 지표", "", "")]
    [InlineData("코스피", "A", "성장성", "", "")]
    [InlineData("코스피", "A", "성장성 지표", "LINE_GRAPH", "")]
    [InlineData("코스피", " A", "성장성 지표", "", "")]
    [InlineData("코스피", "A", "성장성 지표", "", "0059-30")]
    public void Manual_chart_requests_reject_ambiguous_market_graphic_and_code_fields(
        string group,
        string subject,
        string graphic,
        string subtype,
        string dataCode)
    {
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5079Request(
                Entry("5079", group, subject, graphic, subtype, dataCode)));
    }

    [Theory]
    [InlineData("전체", "지수", "개인과기관 매매동향", "라인그래프")]
    [InlineData("코스피", "지수", "개인 매매동향", "라인그래프")]
    [InlineData("전체", "시장", "개인 매매동향", "라인그래프")]
    [InlineData("전체", "지수", "개인 매매동향", "라인 그래프")]
    public void S5083_rejects_legacy_contains_ambiguities(
        string group,
        string subject,
        string graphic,
        string subtype)
    {
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5083Request(
                Entry("5083", group, subject, graphic, subtype)));
    }

    [Theory]
    [InlineData("코스피", "코스닥 매매동향")]
    [InlineData("코스닥", "코스피 매매동향")]
    [InlineData("전체", "코스피 매매동향")]
    [InlineData("코스피", "코스피와코스닥 매매동향")]
    public void S5084_rejects_mismatched_code_and_forCutInfo(
        string group,
        string graphic)
    {
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5084Request(
                Entry("5084", group, "지수", graphic, "라인그래프")));
    }

    [Fact]
    public void Cut_specific_APIs_reject_wrong_cut_missing_selection_and_unsafe_fields()
    {
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5078Request(
                Entry("5079", "해외지수", "다우", "미국업종")));
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5079Request(new LegacyPlaylistEntry("entry", "5079")));
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.Resolve(Entry("9999", "", "", "")));
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5080Request(
                Entry("5080", "코스피", "A\r\n", "매출액")));
        Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5080Request(
                Entry("5080", "코스피", new string('A', 257), "매출액")));
    }

    [Fact]
    public void Resolver_errors_do_not_echo_selected_values()
    {
        const string sensitive = "SENSITIVE-STOCK-SELECTION";
        var exception = Assert.Throws<LegacySceneDataException>(() =>
            _resolver.CreateS5079Request(
                Entry("5079", "UNKNOWN", sensitive, "성장성 지표")));

        Assert.DoesNotContain(sensitive, exception.Message, StringComparison.Ordinal);
    }

    private static LegacyPlaylistEntry Entry(
        string cutCode,
        string group,
        string subject,
        string graphic,
        string subtype = "",
        string dataCode = "") => new(
        "entry",
        cutCode,
        Selection: new LegacySceneSelection(
            group,
            subject,
            graphic,
            subtype,
            dataCode));
}
