"""TTS 文本分段工具单元测试."""

import pytest

from packages.application.tts_job.text_splitter import split_text


class TestSplitTextEmpty:
    """空文本测试"""

    def test_empty_string(self):
        """空字符串返回空列表."""
        assert split_text("") == []

    def test_only_whitespace(self):
        """纯空白文本返回空列表."""
        assert split_text("   \n  \t  ") == []

    def test_none_not_allowed(self):
        """None 会抛出异常（不是我们的职责）."""
        with pytest.raises(AttributeError):
            split_text(None)  # type: ignore


class TestSplitTextShort:
    """短文本测试"""

    def test_short_text_one_segment(self):
        """短文本返回一个段落."""
        text = "你好，世界。"
        result = split_text(text, max_chars=500)
        assert len(result) == 1
        assert result[0] == text

    def test_exactly_max_chars(self):
        """刚好等于 max_chars 的文本返回一个段落."""
        text = "a" * 500
        result = split_text(text, max_chars=500)
        assert len(result) == 1
        assert len(result[0]) == 500

    def test_one_under_max(self):
        """max_chars-1 的文本返回一个段落."""
        text = "a" * 499
        result = split_text(text, max_chars=500)
        assert len(result) == 1
        assert len(result[0]) == 499


class TestSplitTextSentenceBoundary:
    """句子边界分段测试"""

    def test_split_at_period(self):
        """在句号处拆分."""
        text = "第一句。第二句。第三句。"
        # 每句5字符，max_chars=10，每次两句就接近10
        result = split_text(text, max_chars=10)
        assert len(result) >= 2
        # 所有段落都不超过 max_chars
        for seg in result:
            assert len(seg) <= 10

    def test_split_at_exclamation(self):
        """在感叹号处拆分."""
        text = "好棒！真的好棒！太厉害了！"
        result = split_text(text, max_chars=10)
        assert len(result) >= 2
        for seg in result:
            assert len(seg) <= 10

    def test_split_at_question(self):
        """在问号处拆分."""
        text = "你好吗？你是谁？你在哪？"
        result = split_text(text, max_chars=10)
        assert len(result) >= 2
        for seg in result:
            assert len(seg) <= 10

    def test_split_at_newline(self):
        """在换行处拆分."""
        text = "第一段\n第二段\n第三段"
        result = split_text(text, max_chars=10)
        assert len(result) >= 2
        for seg in result:
            assert len(seg) <= 10

    def test_split_at_semicolon(self):
        """在分号处拆分."""
        text = "第一项；第二项；第三项；"
        result = split_text(text, max_chars=10)
        assert len(result) >= 2

    def test_english_punctuation(self):
        """英文标点也能拆分."""
        text = "Hello world. How are you? I am fine!"
        result = split_text(text, max_chars=20)
        assert len(result) >= 2
        for seg in result:
            assert len(seg) <= 20

    def test_mixed_punctuation(self):
        """中英文标点混合."""
        text = "你好！Hello. 你好吗？How are you?"
        result = split_text(text, max_chars=15)
        assert len(result) >= 2


class TestSplitTextForceSplit:
    """强制分段测试"""

    def test_very_long_sentence_forced_split(self):
        """超长单句强制分段."""
        text = "a" * 1000  # 没有标点的长文本
        result = split_text(text, max_chars=100)
        assert len(result) == 10
        for seg in result:
            assert len(seg) == 100

    def test_mixed_long_and_short_sentences(self):
        """长短句混合."""
        long = "我" * 200
        text = f"短句。{long}。短句。"
        result = split_text(text, max_chars=100)
        # 所有段都不超过100
        for seg in result:
            assert len(seg) <= 100
        # 至少有3段（长句被强制拆分）
        assert len(result) >= 3


class TestSplitTextMerging:
    """短段落合并测试"""

    def test_short_segments_merged(self):
        """多个短段合并为一个."""
        # 生成5个短句，每句5字符，max_chars=100，应该合并成一段
        text = "一。二。三。四。五。"
        result = split_text(text, max_chars=100)
        assert len(result) == 1
        assert len(result[0]) <= 100

    def test_merge_within_limit(self):
        """合并后不超过 max_chars."""
        # 10个短句，每句4字符 = 40字符
        text = "句子。" * 10
        result = split_text(text, max_chars=100)
        assert len(result) == 1
        assert len(result[0]) <= 100

    def test_merge_across_multiple(self):
        """多个短段依次合并."""
        text = "短。" * 30  # 30个短句，每句2字符=60字符
        result = split_text(text, max_chars=100)
        assert len(result) == 1
        assert len(result[0]) == 60  # 全部合并


class TestSplitTextChinese:
    """中文文本测试"""

    def test_chinese_paragraph(self):
        """典型中文段落."""
        text = (
            "在一个阳光明媚的早晨，小明来到了公园。"
            "他看到了很多人在锻炼身体。"
            "有的人在跑步，有的人在打太极，还有的人在跳舞。"
            "小明也加入了他们，开始了愉快的一天。"
        )
        result = split_text(text, max_chars=50)
        assert len(result) >= 2
        for seg in result:
            assert len(seg) <= 50
        # 重新拼回应该等于原文本（除了可能的空格处理）
        combined = "".join(result)
        assert combined == text.replace(" ", "")  # strip 不影响中文字符

    def test_chinese_long_paragraph(self):
        """长中文段落."""
        text = "这是一个测试句子。" * 100  # 100个句子
        result = split_text(text, max_chars=200)
        assert len(result) > 1
        for seg in result:
            assert len(seg) <= 200
        # 总字符数不变
        assert sum(len(s) for s in result) == len(text)


class TestSplitTextCustomMaxChars:
    """自定义 max_chars 测试"""

    def test_small_max_chars(self):
        """很小的 max_chars."""
        text = "一二三四五六七八九十。"
        result = split_text(text, max_chars=5)
        for seg in result:
            assert len(seg) <= 5

    def test_large_max_chars(self):
        """很大的 max_chars（不拆分）."""
        text = "这是一段测试文本。" * 10
        result = split_text(text, max_chars=10000)
        assert len(result) == 1

    def test_max_chars_zero(self):
        """max_chars=0 时的行为."""
        text = "测试文本。"
        # 0 会导致每加一个字符就触发强制分段
        result = split_text(text, max_chars=0)
        # 每个字符一段？或者至少有结果
        assert isinstance(result, list)
        assert len(result) > 0

    def test_max_chars_one(self):
        """max_chars=1."""
        text = "abc"
        result = split_text(text, max_chars=1)
        assert len(result) == 3
        assert result == ["a", "b", "c"]


class TestSplitTextPreservesContent:
    """内容完整性测试"""

    def test_preserves_all_chars(self):
        """分段后拼接等于原文（忽略空白调整）."""
        text = "第一句。第二句！第三句？第四句。第五句。"
        result = split_text(text, max_chars=10)
        combined = "".join(result)
        assert combined == text

    def test_no_empty_segments(self):
        """没有空字符串段落."""
        text = "句子。。。双标点。"
        result = split_text(text, max_chars=10)
        assert all(seg for seg in result)  # 所有段非空

    def test_stripped_segments(self):
        """段落首尾没有多余空白."""
        text = "  第一句。  第二句。  "
        result = split_text(text, max_chars=10)
        for seg in result:
            assert seg == seg.strip()


class TestSplitTextEdgeCases:
    """边界情况测试"""

    def test_single_char(self):
        """单字符."""
        result = split_text("我", max_chars=10)
        assert len(result) == 1
        assert result[0] == "我"

    def test_only_punctuation(self):
        """纯标点."""
        text = "。。。！！？？"
        result = split_text(text, max_chars=5)
        assert len(result) >= 1
        assert sum(len(s) for s in result) == len(text)

    def test_numbers_and_symbols(self):
        """数字和符号."""
        text = "第1章。第2节。第3段。"
        result = split_text(text, max_chars=10)
        assert len(result) >= 1
        assert all(len(s) <= 10 for s in result)

    def test_mixed_chinese_english(self):
        """中英文混合."""
        text = "Hello你好World世界。Test测试。"
        result = split_text(text, max_chars=10)
        assert len(result) >= 2
        assert all(len(s) <= 10 for s in result)

    def test_consecutive_punctuation(self):
        """连续标点."""
        text = "真的吗！？不对。。。好吧。"
        result = split_text(text, max_chars=20)
        assert len(result) >= 1
        combined = "".join(result)
        assert combined == text


class TestSplitTextDefaultParams:
    """默认参数测试"""

    def test_default_max_chars_is_500(self):
        """默认 max_chars=500."""
        text = "a" * 500
        result = split_text(text)
        assert len(result) == 1

        text2 = "a" * 501
        result2 = split_text(text2)
        assert len(result2) >= 2
