"""question_units helper 单元测试：组装/展开/校验/单元正确性。

覆盖 pair 契约唯一入口的核心行为：
- build_units 聚合孪生对、保留 single；
- 孤儿 pair、角色缺失/重复直接报错（fail-fast）；
- flatten_units 无损展开；
- unit_correctness 对 pair 走 AND、缺题走 KeyError（防静默）。
"""

import pytest

from app.harness.question_units import (
    build_units,
    flatten_units,
    unit_correctness,
    validate_units,
)
from core.types import GeneratedQuestion


def _q(qid: str, role: str = "single", pid: str | None = None) -> GeneratedQuestion:
    """构造测试题目；pid 非空时视为孪生对成员。"""
    return GeneratedQuestion(
        question_id=qid,
        video_id="v",
        task_type="AR",
        question="?",
        options=("A. a", "B. b", "C. c", "D. d"),
        answer="A",
        source_nodes=("n",),
        difficulty="hard",
        pair_id=pid,
        question_role=role,
        unit_id=pid or qid,
        flip_axis="ax" if pid else None,
    )


def test_build_units_groups_pair_and_keeps_single():
    qs = [_q("s1"), _q("po", "pair_original", "p"), _q("pm", "pair_mirror", "p")]
    units = build_units(qs)
    kinds = sorted(u.kind for u in units)
    assert kinds == ["pair", "single"]


def test_validate_units_rejects_orphan_pair():
    with pytest.raises(ValueError):
        validate_units(build_units([_q("po", "pair_original", "p")]))  # 只 1 条


def test_flatten_roundtrip():
    qs = [_q("po", "pair_original", "p"), _q("pm", "pair_mirror", "p")]
    assert {q.question_id for q in flatten_units(build_units(qs))} == {"po", "pm"}


def test_unit_correctness_bidirectional_and():
    qs = [_q("po", "pair_original", "p"), _q("pm", "pair_mirror", "p")]
    u = build_units(qs)[0]
    assert unit_correctness(u, {"po": True, "pm": True}) is True
    assert unit_correctness(u, {"po": True, "pm": False}) is False  # AND


def test_build_units_rejects_duplicate_role():
    qs = [_q("po1", "pair_original", "p"), _q("po2", "pair_original", "p")]
    with pytest.raises(ValueError):
        build_units(qs)


def test_unit_correctness_missing_question_raises_keyerror():
    qs = [_q("po", "pair_original", "p"), _q("pm", "pair_mirror", "p")]
    u = build_units(qs)[0]
    with pytest.raises(KeyError):
        unit_correctness(u, {"po": True})  # 缺 pm → KeyError 防静默
