"""refresh_t2i_prompt_hash primitive — AC-A1."""
import pytest
from app.core.steps._owned_helpers import (
    OWNED_SENTINEL_SCHEMA_VERSION, OWNED_VALIDATOR_FULL,
    compute_t2i_prompt_hash, compute_owned_hash, compute_camera_direction_hash,
    refresh_t2i_prompt_hash,
)
from app.core.errors import AppError


def _valid_sentinel(t2i: str = "old prompt") -> dict:
    return {
        "schema_version": OWNED_SENTINEL_SCHEMA_VERSION,
        "t2i_prompt_hash": compute_t2i_prompt_hash(t2i),
        "owned_hash": compute_owned_hash(["C01", "O02"]),
        "camera_direction_hash": compute_camera_direction_hash("dolly in"),
        "owned_usage_hash": "0123456789abcdef",  # C2 v1 sentinel v2
        "validator": OWNED_VALIDATOR_FULL,
        "violations": [],
    }


def test_refresh_changes_only_t2i_prompt_hash():
    """AC-A1: t2i_prompt_hash 만 갱신, 다른 sentinel 필드 모두 보존."""
    sentinel = _valid_sentinel("old prompt")
    pre_owned = sentinel["owned_hash"]
    pre_camera = sentinel["camera_direction_hash"]
    pre_validator = sentinel["validator"]
    pre_schema = sentinel["schema_version"]
    # T1 review M4 (Codex+Claude 합의): violations 도 보존 검증 — list 복사 후 비교.
    pre_violations = list(sentinel["violations"])

    changed = refresh_t2i_prompt_hash(sentinel, "NEW prompt", where="test1")

    assert changed is True
    assert sentinel["t2i_prompt_hash"] == compute_t2i_prompt_hash("NEW prompt")
    assert sentinel["owned_hash"] == pre_owned
    assert sentinel["camera_direction_hash"] == pre_camera
    assert sentinel["validator"] == pre_validator
    assert sentinel["schema_version"] == pre_schema
    assert sentinel["violations"] == pre_violations


def test_refresh_noop_when_already_matching():
    sentinel = _valid_sentinel("same prompt")
    changed = refresh_t2i_prompt_hash(sentinel, "same prompt", where="test2")
    assert changed is False


def test_refresh_raises_on_invalid_sentinel():
    """AC-A1: shape 위반 sentinel → AppError(step.contract_violation) raise."""
    bad = {"schema_version": 1}  # 다른 필드 없음 → shape 위반
    with pytest.raises(AppError) as exc:
        refresh_t2i_prompt_hash(bad, "p", where="test3")
    # AppError 는 super().__init__() 에 message 미전달 → str(exc) == "" .
    # 코드베이스 패턴 (test_owned_helpers.py) 에 맞춰 .message + .code 로 검증.
    # T1 review M1 (Claude): error code assert — codebase 표준 (assert_owned_sentinel_shape
    # 모든 raise 는 step.contract_violation, _owned_helpers.py:190+) 일치.
    assert exc.value.code == "step.contract_violation"
    msg = exc.value.message.lower()
    assert "owned_validation" in msg or "missing" in msg
