"""Subtitle 领域模型单测."""

import pytest

from packages.domain.subtitle import SubtitleSegment, SubtitleTimeline, SubtitleWord


class TestSubtitleWord:
    def test_duration_normal(self):
        word = SubtitleWord(text="你好", start=1.0, end=2.5)
        assert word.duration == pytest.approx(1.5)

    def test_duration_zero(self):
        word = SubtitleWord(text="啊", start=3.0, end=3.0)
        assert word.duration == 0.0

    def test_duration_negative_returns_zero(self):
        word = SubtitleWord(text="test", start=5.0, end=3.0)
        assert word.duration == 0.0


class TestSubtitleSegment:
    def test_duration(self):
        seg = SubtitleSegment(text="大家好", start=0.0, end=3.0)
        assert seg.duration == pytest.approx(3.0)

    def test_char_count(self):
        seg = SubtitleSegment(text="今天天气真好", start=0.0, end=5.0)
        assert seg.char_count == 6

    def test_empty_text(self):
        seg = SubtitleSegment(text="", start=0.0, end=1.0)
        assert seg.char_count == 0

    def test_default_words_empty(self):
        seg = SubtitleSegment(text="test", start=0.0, end=1.0)
        assert seg.words == []


class TestSubtitleTimeline:
    def test_empty_timeline(self):
        tl = SubtitleTimeline()
        assert tl.segment_count == 0
        assert tl.total_chars == 0
        assert tl.language == "zh"
        assert tl.total_duration == 0.0

    def test_segment_count(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="第一段", start=0.0, end=2.0),
                SubtitleSegment(text="第二段", start=2.0, end=5.0),
            ]
        )
        assert tl.segment_count == 2
        assert tl.total_chars == 6

    def test_total_chars(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="abc", start=0, end=1),
                SubtitleSegment(text="defg", start=1, end=2),
            ]
        )
        assert tl.total_chars == 7


class TestMergeShortSegments:
    def test_single_segment_no_change(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="你好", start=0.0, end=1.0),
            ]
        )
        result = tl.merge_short_segments(min_chars=8)
        assert result.segment_count == 1
        assert result.segments[0].text == "你好"

    def test_empty_timeline(self):
        tl = SubtitleTimeline()
        result = tl.merge_short_segments()
        assert result.segment_count == 0

    def test_merge_short_segments(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="你好", start=0.0, end=1.0),
                SubtitleSegment(text="今天", start=1.0, end=2.0),
                SubtitleSegment(text="天气", start=2.0, end=3.0),
                SubtitleSegment(text="真好", start=3.0, end=4.0),
            ]
        )
        result = tl.merge_short_segments(min_chars=4)
        # 每段2字，min=4，应该每2段合并
        assert result.segment_count == 2
        assert result.segments[0].text == "你好今天"
        assert result.segments[0].start == 0.0
        assert result.segments[0].end == 2.0
        assert result.segments[1].text == "天气真好"
        assert result.segments[1].start == 2.0
        assert result.segments[1].end == 4.0

    def test_remaining_merged_to_last(self):
        # 3段，每段2字，min=5 → 前5字合并，剩余1字并到最后
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="一二", start=0, end=1),
                SubtitleSegment(text="三四", start=1, end=2),
                SubtitleSegment(text="五", start=2, end=3),
            ]
        )
        result = tl.merge_short_segments(min_chars=5)
        assert result.segment_count == 1
        assert result.segments[0].text == "一二三四五"

    def test_merge_with_words(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(
                    text="你好",
                    start=0.0,
                    end=1.0,
                    words=[
                        SubtitleWord(text="你", start=0.0, end=0.5),
                        SubtitleWord(text="好", start=0.5, end=1.0),
                    ],
                ),
                SubtitleSegment(
                    text="世界",
                    start=1.0,
                    end=2.0,
                    words=[
                        SubtitleWord(text="世", start=1.0, end=1.5),
                        SubtitleWord(text="界", start=1.5, end=2.0),
                    ],
                ),
            ]
        )
        result = tl.merge_short_segments(min_chars=10)
        assert result.segment_count == 1
        assert len(result.segments[0].words) == 4


class TestSplitLongSegments:
    def test_short_segments_no_split(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="短文本", start=0.0, end=1.0),
            ]
        )
        result = tl.split_long_segments(max_chars=20)
        assert result.segment_count == 1

    def test_split_by_punctuation(self):
        text = "今天天气真好。我们出去玩吧！"
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text=text, start=0.0, end=5.0),
            ]
        )
        result = tl.split_long_segments(max_chars=10)
        assert result.segment_count >= 2
        # 合并起来应该等于原文
        assert "".join(s.text for s in result.segments) == text

    def test_split_preserves_time_order(self):
        tl = SubtitleTimeline(
            segments=[
                SubtitleSegment(text="一二三四五六七八九十。十一二三四五六七八九十。", start=0.0, end=10.0),
            ]
        )
        result = tl.split_long_segments(max_chars=10)
        # 时间应该是递增的
        for i in range(len(result.segments) - 1):
            assert result.segments[i].end <= result.segments[i + 1].start + 0.001

    def test_empty_timeline(self):
        tl = SubtitleTimeline()
        result = tl.split_long_segments()
        assert result.segment_count == 0


class TestSplitTextByPunctuation:
    def test_no_punctuation_short(self):
        result = SubtitleTimeline._split_text_by_punctuation("你好世界", 20)
        assert len(result) == 1
        assert result[0] == "你好世界"

    def test_sentence_end_punctuation_long_enough(self):
        # 每段超过 max_chars//2 才会在句末标点断开
        text = "今天天气真的非常好。明天天气也不错。"
        result = SubtitleTimeline._split_text_by_punctuation(text, 10)
        assert len(result) >= 2
        assert "".join(result) == text

    def test_short_text_with_punctuation_no_split(self):
        # 文本太短（< max_chars//2），即使有标点也不断开
        result = SubtitleTimeline._split_text_by_punctuation("你好。世界。", 20)
        assert len(result) == 1

    def test_long_text_hard_split(self):
        text = "一二三四五六七八九十十一二三四五六七八九十"
        result = SubtitleTimeline._split_text_by_punctuation(text, 10)
        assert len(result) >= 2
        assert "".join(result) == text

    def test_empty_text(self):
        result = SubtitleTimeline._split_text_by_punctuation("", 10)
        assert result == []


class TestMergeSegments:
    def test_merge_two_segments(self):
        segs = [
            SubtitleSegment(text="你好", start=0.0, end=1.0),
            SubtitleSegment(text="世界", start=1.0, end=2.0),
        ]
        result = SubtitleTimeline._merge_segments(segs)
        assert result.text == "你好世界"
        assert result.start == 0.0
        assert result.end == 2.0

    def test_merge_empty_list(self):
        result = SubtitleTimeline._merge_segments([])
        assert result.text == ""
        assert result.start == 0
        assert result.end == 0
