"""채점(outcome) 산출 단일 소스 (study-to-viewer P2).

라이브 attempt 엔드포인트(submit_attempt)와 뷰어 ingest 가 **동일 함수**로 채점 →
정오 어휘가 한 곳(서버)에서 결정(plan r2: ingest 는 raw 신호 selected+unsure 만 싣고
DS 가 산출 = '무수정 재생'을 실제로 성립시키는 형태). correct_choice 는 항상 현재 DB 값.

규칙(라이브 study_questions.py:1008-1020 동일):
  is_unsure=True  → (None, False, 'unsure')   # unsure 가 정오 override, selected 폐기
  selected None   → ValueError                # 선택 없고 unsure 도 아니면 무효(엔드포인트가 처리)
  그 외          → selected==correct → (selected, is_correct, 'correct'|'wrong')
"""

from __future__ import annotations


def derive_outcome(
    selected_choice: int | None, is_unsure: bool, correct_choice: int
) -> tuple[int | None, bool, str]:
    """(selected, is_correct, outcome) 반환. skipped 는 여기서 안 나옴(선택 없으면 호출측이 거부/skip)."""
    if is_unsure:
        return None, False, "unsure"
    if selected_choice is None:
        raise ValueError("selected_choice (1~4) 또는 is_unsure=true 가 필요합니다")
    is_correct = selected_choice == correct_choice
    return selected_choice, is_correct, ("correct" if is_correct else "wrong")
