"""字幕模块单元测试。"""

from __future__ import annotations

from app.tree.subtitle import (
    SRTEntry,
    assign_subtitles_voronoi,
    check_subtitle_completeness,
    extract_subtitle_for_range,
    parse_srt,
)

_SAMPLE_SRT = """\
1
00:00:01,000 --> 00:00:03,500
Hello world.

2
00:00:05,000 --> 00:00:08,000
<i>This is italic</i> text.

3
00:00:10,000 --> 00:00:12,000
Final line.
"""


class TestParseSrt:
    def test_basic_parse(self, tmp_path):
        srt_file = tmp_path / "test.srt"
        srt_file.write_text(_SAMPLE_SRT, encoding="utf-8")
        entries = parse_srt(str(srt_file))
        assert len(entries) == 3
        assert entries[0] == SRTEntry(start=1.0, end=3.5, text="Hello world.")
        assert entries[1].text == "This is italic text."

    def test_empty_srt(self, tmp_path):
        srt_file = tmp_path / "empty.srt"
        srt_file.write_text("", encoding="utf-8")
        entries = parse_srt(str(srt_file))
        assert entries == []

    def test_malformed_srt_skips_bad_blocks(self, tmp_path):
        bad_srt = "garbage\n\n1\n00:00:01,000 --> 00:00:02,000\nGood line.\n"
        srt_file = tmp_path / "bad.srt"
        srt_file.write_text(bad_srt, encoding="utf-8")
        entries = parse_srt(str(srt_file))
        assert len(entries) == 1
        assert entries[0].text == "Good line."


class TestCompletenessCheck:
    def test_good_coverage(self):
        entries = [SRTEntry(0.0, 5.0, "a"), SRTEntry(5.0, 10.0, "b")]
        report = check_subtitle_completeness(entries, duration=10.0, min_coverage=0.5)
        assert report.usable is True
        assert report.coverage_ratio >= 0.5

    def test_poor_coverage(self):
        entries = [SRTEntry(0.0, 1.0, "short")]
        report = check_subtitle_completeness(entries, duration=100.0, min_coverage=0.3)
        assert report.usable is False

    def test_max_gap(self):
        entries = [SRTEntry(0.0, 1.0, "a"), SRTEntry(50.0, 51.0, "b")]
        report = check_subtitle_completeness(entries, duration=60.0)
        assert report.max_gap_sec >= 49.0


class TestExtractForRange:
    def test_overlap(self):
        entries = [
            SRTEntry(0.0, 5.0, "first"),
            SRTEntry(4.0, 8.0, "second"),
            SRTEntry(10.0, 12.0, "third"),
        ]
        text = extract_subtitle_for_range(entries, (3.0, 9.0))
        assert "first" in text
        assert "second" in text
        assert "third" not in text


class TestVoronoiAssign:
    def test_assigns_to_l3_nodes(self):
        from app.tree.index import (
            IndexMeta,
            L1Card,
            L1Node,
            L2Card,
            L2Node,
            L3Card,
            L3Node,
            TreeIndex,
        )

        l3_0 = L3Node(id="l1_0_l2_0_l3_0", card=L3Card("desc0", [], [], [], "", {}), timestamp=2.0)
        l3_1 = L3Node(id="l1_0_l2_0_l3_1", card=L3Card("desc1", [], [], [], "", {}), timestamp=6.0)
        l2 = L2Node(
            id="l1_0_l2_0",
            card=L2Card("evt", [], [], [], [], "", None),
            time_range=(0.0, 10.0),
            children=[l3_0, l3_1],
        )
        l1 = L1Node(
            id="l1_0",
            card=L1Card("scene", "", [], [], [], [], ""),
            time_range=(0.0, 10.0),
            children=[l2],
        )
        index = TreeIndex(metadata=IndexMeta("/test.mp4", "video"), roots=[l1])

        entries = [SRTEntry(1.0, 3.0, "hello"), SRTEntry(5.0, 7.0, "world")]
        assign_subtitles_voronoi(index, entries)

        assert l3_0.card.subtitle != ""
        assert "hello" in l3_0.card.subtitle
        assert l3_1.card.subtitle != ""
        assert "world" in l3_1.card.subtitle
        # L2 字幕应聚合 L3 子节点字幕
        assert l2.card.subtitle != ""
        assert "hello" in l2.card.subtitle
        assert "world" in l2.card.subtitle
