"""anu_v2.tests.test_owner_trigger_decision_schema_2554 — decision JSON v1 schema 회귀 (task-2554).

회장 §명시 14장 §5 1:1: schema ``anu_v2.owner_trigger_decision.v1``,
8 실행 조건 fail-closed, ``additionalProperties: false`` 강제.
"""

from __future__ import annotations

import sys
from pathlib import Path

import pytest

WORKSPACE_ROOT = Path(__file__).resolve().parents[2]
if str(WORKSPACE_ROOT) not in sys.path:
    sys.path.insert(0, str(WORKSPACE_ROOT))

from anu_v2.owner_trigger_decision import (  # noqa: E402
    ALLOWED_ACTION,
    ALLOWED_COMMENT_BODY,
    DecisionInvalidError,
    REQUIRED_KEYS,
    SCHEMA_NAME,
    validate_decision,
)


_HEAD_A = "a" * 40
_HEAD_B = "b" * 40


def _valid_decision(**overrides):
    base = {
        "schema": SCHEMA_NAME,
        "task_id": "task-2554",
        "pr": 103,
        "current_head": _HEAD_A,
        "queue_head": True,
        "current_head_confirmed": True,
        "gemini_evidence_fresh": False,
        "nudge_count_for_pr_head": 0,
        "allowed_action": ALLOWED_ACTION,
        "comment_body": ALLOWED_COMMENT_BODY,
        "allowed": True,
    }
    base.update(overrides)
    return base


def test_schema_name_constant_is_fixed():
    assert SCHEMA_NAME == "anu_v2.owner_trigger_decision.v1"


def test_allowed_action_constant_is_fixed():
    assert ALLOWED_ACTION == "POST_GEMINI_REVIEW_TRIGGER_COMMENT"


def test_allowed_comment_body_constant_is_fixed():
    assert ALLOWED_COMMENT_BODY == "/gemini review"


def test_valid_decision_passes():
    result = validate_decision(_valid_decision())
    assert result["allowed"] is True


def test_extra_keys_blocked_additional_properties_false():
    d = _valid_decision()
    d["secret_token"] = "ghp_AAAA"  # extra key
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_ADDITIONAL_PROPERTIES"


def test_missing_required_key_fails():
    d = _valid_decision()
    del d["queue_head"]
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_MISSING_KEYS"


def test_wrong_schema_name_fails():
    d = _valid_decision(schema="anu_v2.owner_trigger_decision.v2")
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_SCHEMA"


def test_wrong_action_fails():
    d = _valid_decision(allowed_action="POST_ARBITRARY_COMMENT")
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_ACTION"


def test_wrong_comment_body_fails():
    d = _valid_decision(comment_body="/gemini approve")
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_COMMENT_BODY"


def test_allowed_false_fails_closed():
    d = _valid_decision(allowed=False)
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_NOT_ALLOWED"


def test_current_head_short_fails():
    d = _valid_decision(current_head="abc")
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_HEAD_FORMAT"


def test_current_head_non_hex_fails():
    d = _valid_decision(current_head="z" * 40)
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_HEAD_FORMAT"


def test_pr_must_be_int_not_bool():
    d = _valid_decision(pr=True)  # bool은 int subclass라도 차단해야 함
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d)
    assert exc.value.code == "E_TYPE"


def test_actual_head_mismatch_fails():
    d = _valid_decision(current_head=_HEAD_A)
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision(d, current_head_actual=_HEAD_B)
    assert exc.value.code == "E_HEAD_MISMATCH"


def test_actual_head_match_passes():
    d = _valid_decision(current_head=_HEAD_A)
    assert validate_decision(d, current_head_actual=_HEAD_A)["pr"] == 103


def test_not_a_dict_fails():
    with pytest.raises(DecisionInvalidError) as exc:
        validate_decision("not-a-dict")  # type: ignore[arg-type]
    assert exc.value.code == "E_NOT_DICT"


def test_required_keys_completeness():
    # 11 keys 모두 schema에 박제됨을 확인 — REQUIRED_KEYS 변경이 schema 변경을 동반함을 보장.
    assert set(REQUIRED_KEYS) == {
        "schema",
        "task_id",
        "pr",
        "current_head",
        "queue_head",
        "current_head_confirmed",
        "gemini_evidence_fresh",
        "nudge_count_for_pr_head",
        "allowed_action",
        "comment_body",
        "allowed",
    }
