"""#1749 问题 C：跨视频素材级去重 + target_durations 测试。"""

import random

import pytest

from packages.domain.variant_plan_selector import (
    BATCH_CLIP_OVERLAP_LIMIT,
    _clip_overlap_ratio,
    reselect_clips_for_variant,
)


def _src_clips(n=3, dur=5.0):
    return [
        {
            "order": i,
            "asset_id": f"src{i}",
            "start_time": 0.0,
            "duration": dur,
            "clip_type": "main",
            "transition_effect": "cut",
            "transition_duration": 0.0,
        }
        for i in range(n)
    ]


def test_three_variants_three_clips_eleven_assets_no_cross_reuse():
    """3 变体 × 3 片段 / 11 素材：fresh 优先 → 跨变体零重复。"""
    pool = [f"a{i}" for i in range(11)]
    durs = {a: 30.0 for a in pool}
    batch: dict = {}
    used_per_variant = []
    for v in range(3):
        clips = reselect_clips_for_variant(
            _src_clips(3), pool, asset_durations=durs, batch_segments=batch, rng=random.Random(100 + v)
        )
        assert len(clips) == 3
        used_per_variant.append({c["asset_id"] for c in clips})
    # 两两交集为空（9 个素材位置，11 素材足够 fresh 分配）
    assert used_per_variant[0] & used_per_variant[1] == set()
    assert used_per_variant[0] & used_per_variant[2] == set()
    assert used_per_variant[1] & used_per_variant[2] == set()


def test_reuse_overlap_under_limit_and_no_full_overlap():
    """素材池不足被迫复用时：重叠 ≤20% 且不得完全重叠。"""
    # 2 个长素材、3 变体 × 3 片段 → 必然复用
    pool = ["x", "y"]
    durs = {"x": 60.0, "y": 60.0}
    batch: dict = {}
    for v in range(3):
        reselect_clips_for_variant(
            _src_clips(3, 5.0), pool, asset_durations=durs, batch_segments=batch, rng=random.Random(7 + v)
        )
    # 校验 batch_segments 中同素材任意两区间重叠占比
    for asset, segs in batch.items():
        for i in range(len(segs)):
            for j in range(i + 1, len(segs)):
                s1, e1 = segs[i]
                s2, e2 = segs[j]
                ov = max(0.0, min(e1, e2) - max(s1, s2))
                seg_dur = min(e1 - s1, e2 - s2)
                ratio = ov / seg_dur if seg_dur > 0 else 0.0
                assert ratio <= BATCH_CLIP_OVERLAP_LIMIT + 0.01, f"{asset} overlap {ratio}"
                # 不得完全重叠
                assert not (abs(s1 - s2) < 0.01 and abs(e1 - e2) < 0.01), f"{asset} 完全重叠"


def test_short_asset_cannot_be_reused_across_variants():
    """短素材（时长 < 段长 80%）数学上无法错开 → 禁跨变体复用。"""
    pool = ["short", "long1", "long2"]
    durs = {"short": 6.2, "long1": 40.0, "long2": 40.0}
    batch = {"short": [(0.0, 6.2)]}  # 短素材已被变体0使用
    clips = reselect_clips_for_variant(
        _src_clips(1, 10.0), pool, asset_durations=durs, batch_segments=batch, rng=random.Random(1)
    )
    assert clips[0]["asset_id"] != "short"


def test_target_durations_applied_to_clips():
    """target_durations 落库到片段 duration。"""
    pool = ["a", "b", "c"]
    durs = {"a": 30.0, "b": 30.0, "c": 30.0}
    clips = reselect_clips_for_variant(
        _src_clips(3, 5.0),
        pool,
        asset_durations=durs,
        batch_segments={},
        target_durations=[7.333, 7.333, 7.334],
        rng=random.Random(3),
    )
    durs_out = sorted(c["duration"] for c in clips)
    assert durs_out == pytest.approx([7.333, 7.333, 7.334], abs=0.01)


def test_short_asset_freeze_start_zero():
    """素材短于目标段长：起点为 0（末帧冻结由渲染侧铺满），不报错。"""
    pool = ["short6s"]
    durs = {"short6s": 6.0}
    clips = reselect_clips_for_variant(
        _src_clips(1, 10.0),
        pool,
        asset_durations=durs,
        batch_segments={},
        target_durations=[10.0],
        rng=random.Random(5),
    )
    assert clips[0]["asset_id"] == "short6s"
    assert clips[0]["start_time"] == 0.0
    assert clips[0]["duration"] == pytest.approx(10.0)


def test_empty_pool_raises():
    with pytest.raises(ValueError):
        reselect_clips_for_variant(_src_clips(2), [], asset_durations={}, rng=random.Random(1))


def test_empty_source_raises():
    with pytest.raises(ValueError):
        reselect_clips_for_variant([], ["a"], asset_durations={"a": 10.0}, rng=random.Random(1))


def test_zero_duration_assets_raises():
    with pytest.raises(ValueError):
        reselect_clips_for_variant(
            _src_clips(2), ["a", "b"], asset_durations={"a": 0.0, "b": 0.0}, rng=random.Random(1)
        )


def test_overlap_ratio_helper():
    batch = {"a": [(0.0, 5.0)]}
    assert _clip_overlap_ratio("a", 0.0, 5.0, batch) == pytest.approx(1.0)
    assert _clip_overlap_ratio("a", 5.0, 5.0, batch) == pytest.approx(0.0)
    assert _clip_overlap_ratio("a", 4.0, 5.0, batch) == pytest.approx(0.2)
    assert _clip_overlap_ratio("b", 0.0, 5.0, batch) == 0.0
