"""Block B B1 — `CompletionReport.origin` 필드 + backward-compat default.

Plan v2.1.3 / spec V5 §2.1: verify 결과 origin 분류 도입. ResumeDecision 평가 시
사용. B7/B8 (verify_crashed origin) prerequisite — 본 commit scope 는 schema
변경 + default 만, runner 동작 변경 X.

5 origin 값:
  - clean: 정상
  - artifact_missing: DB row / PNG / cp 파일 부재 (default — backward-compat)
  - contract_drift: schema/config_hash mismatch / loader contract / AppError
  - invariant_drift: sentinel/hash drift (mutator/manual/unknown)
  - verify_crashed: verifier 의 unexpected exception
"""
from __future__ import annotations

import pytest

from app.core.integrity_report import CompletionReport


class TestCompletionReportOriginDefault:
    def test_origin_default_is_artifact_missing(self):
        """기존 verifier 가 origin 미지정 시 default 'artifact_missing'.

        backward-compat: 본 commit 진입 전의 모든 CompletionReport(...) call site
        (44 곳) 가 origin 인자 미지정 — default 가 'artifact_missing' 이어야
        의미 변화 없음. ResumeDecision 의 RERUN_SELF + origin='artifact_missing'
        분기 (Block B T1~T3 helper) 와 일치.
        """
        report = CompletionReport(
            is_complete=False,
            missing=["x"],
            severity="missing",
            metadata={},
        )
        assert report.origin == "artifact_missing"

    def test_origin_default_when_complete(self):
        """is_complete=True 인 경우도 default 적용 (호출자가 origin 명시 안 하면)."""
        report = CompletionReport(
            is_complete=True,
            missing=[],
            severity="clean",
            metadata={},
        )
        assert report.origin == "artifact_missing"  # default 적용 (해당 분기에서는 의미 없음)


class TestCompletionReportOriginExplicit:
    def test_origin_can_be_overridden_to_clean(self):
        report = CompletionReport(
            is_complete=True,
            missing=[],
            severity="clean",
            metadata={},
            origin="clean",
        )
        assert report.origin == "clean"

    def test_origin_can_be_overridden_to_contract_drift(self):
        report = CompletionReport(
            is_complete=False,
            missing=["loader violation"],
            severity="missing",
            metadata={"app_error_code": "step.contract_violation"},
            origin="contract_drift",
        )
        assert report.origin == "contract_drift"

    def test_origin_can_be_overridden_to_invariant_drift(self):
        report = CompletionReport(
            is_complete=False,
            missing=["sentinel"],
            severity="partial",
            metadata={},
            origin="invariant_drift",
        )
        assert report.origin == "invariant_drift"

    def test_origin_can_be_overridden_to_verify_crashed(self):
        report = CompletionReport(
            is_complete=False,
            missing=["verify_crashed: KeyError"],
            severity="missing",
            metadata={"crash": "KeyError"},
            origin="verify_crashed",
        )
        assert report.origin == "verify_crashed"


class TestCompletionReportFrozen:
    def test_origin_frozen_dataclass(self):
        """frozen — origin 사후 변경 차단 (caller 가 mutation 금지)."""
        from dataclasses import FrozenInstanceError

        report = CompletionReport(
            is_complete=True, missing=[], severity="clean", metadata={},
        )
        with pytest.raises(FrozenInstanceError):
            report.origin = "verify_crashed"


class TestCompletionReportBackwardCompat:
    """기존 call site 호환 가드 — 본 commit 이 어떤 production 흐름도 깨지 않음."""

    def test_positional_args_still_work(self):
        """positional 4 arg — 기존 패턴 보존."""
        report = CompletionReport(True, [], "clean", {})
        assert report.is_complete is True
        assert report.missing == []
        assert report.severity == "clean"
        assert report.metadata == {}
        assert report.origin == "artifact_missing"  # default

    def test_keyword_args_without_origin_work(self):
        """keyword args (origin 미지정) — 기존 패턴 보존."""
        report = CompletionReport(
            is_complete=False,
            missing=["foo"],
            severity="partial",
            metadata={"foo": "bar"},
        )
        assert report.is_complete is False
        assert report.origin == "artifact_missing"
