"""anu_v2.tests.test_owner_trigger_201_capability_first_practical_use — task-2557 §Test-2.

회장 §명시 2026-05-12 Track C Rank 1 1:1 박제:
  PR #107 attempt-5 raw 201 evidence (``owner_trigger_201_capability_first_practical_use.json``)
  + attempt-4↔attempt-5 페어 (``owner_trigger_permission_update_no_regen.json``) cross-fixture
  회귀로 capability 첫 실용 활용 사례를 영구 catch.

회귀 catch 6 종:
  1. evidence schema = ``anu_v2.owner_trigger_evidence.owner-trigger-posted.v1``
  2. POST 201 + ``comment_user_login == "JonghyukJeon"`` + comment_id 박제
  3. ``capability_first_practical_use=True`` evidence_source 어셀션
  4. ``owner_manual_input_count=0`` evidence_source 어셀션
  5. cross-fixture: ``token_hash_changed_from_attempt_4 == false`` (fixture 3)
  6. permission_added: ``pull_requests=write`` 1 건 (fixture 3)

본 test 는 fixture 기반 evidence 회귀만 수행 (owner_trigger_only / executor_scheduler 모듈 코드
변경 0 — 회장 §명시 task-2557 금지 12 #12 1:1).
"""

from __future__ import annotations

import json
from pathlib import Path

import pytest


FIXTURES_DIR = Path(__file__).resolve().parents[1] / "fixtures"
FIXTURE_POSTED = FIXTURES_DIR / "owner_trigger_201_capability_first_practical_use.json"
FIXTURE_PAIR = FIXTURES_DIR / "owner_trigger_permission_update_no_regen.json"

EXPECTED_POSTED_SCHEMA = "anu_v2.owner_trigger_evidence.owner-trigger-posted.v1"
EXPECTED_PAIR_SCHEMA = "anu_v2.owner_trigger_evidence.permission-update-no-regen.v1"
EXPECTED_COMMENT_USER = "JonghyukJeon"
EXPECTED_COMMENT_ID = 4429803851
EXPECTED_TOKEN_HASH_PREFIX = "a9e05574"
EXPECTED_ENDPOINT = "/repos/Jeon-Jonghyuk/dev_workspace/issues/107/comments"
EXPECTED_HEAD = "e03f536ad7ad626f1a2afca080d1952588f53a71"


# ─── helpers ──────────────────────────────────────────────────────────────────


def _load_posted() -> dict:
    return json.loads(FIXTURE_POSTED.read_text(encoding="utf-8"))


def _load_pair() -> dict:
    return json.loads(FIXTURE_PAIR.read_text(encoding="utf-8"))


# ─── tests — fixture 2 (POSTED) ───────────────────────────────────────────────


def test_fixture_loads_and_schema_matches_owner_trigger_posted_v1():
    """fixture 2 의 schema 가 owner-trigger-posted.v1 임을 박제."""
    fx = _load_posted()
    assert fx["schema"] == EXPECTED_POSTED_SCHEMA
    assert fx["http_status"] == 201
    assert fx["pr"] == 107
    assert fx["attempt"] == 5
    assert fx["head"] == EXPECTED_HEAD
    assert fx["endpoint"] == EXPECTED_ENDPOINT
    assert fx["method"] == "POST"
    # token redaction 정책.
    assert fx["token_value_logged"] is False
    assert fx["token_present"] is True
    assert fx["token_hash_prefix"] == EXPECTED_TOKEN_HASH_PREFIX
    assert len(fx["token_hash_prefix"]) == 8


def test_post_201_comment_user_login_is_jonghyukjeon_owner_account():
    """POST 201 응답에서 comment_user_login == 'JonghyukJeon' (owner 본인 계정) 박제."""
    fx = _load_posted()
    assert fx["http_status"] == 201
    assert fx["comment_user_login"] == EXPECTED_COMMENT_USER
    assert fx["comment_id"] == EXPECTED_COMMENT_ID
    assert fx["comment_author_association"] == "MEMBER"
    assert fx["comment_body"] == "/gemini review"
    expected_html = f"https://github.com/Jeon-Jonghyuk/dev_workspace/pull/107#issuecomment-{EXPECTED_COMMENT_ID}"
    assert fx["comment_html_url"] == expected_html


def test_evidence_source_capability_first_practical_use_true():
    """evidence_source 에 capability_first_practical_use=True 박제."""
    fx = _load_posted()
    assert fx["capability_first_practical_use"] is True
    assert fx["evidence_source"]["capability_first_practical_use"] is True
    assert fx["evidence_source"]["runner_direct_invocation_count"] == 1


def test_evidence_source_owner_manual_input_count_zero():
    """evidence_source 에 owner_manual_input_count=0 박제 — 회장 수동 /gemini review 0 건."""
    fx = _load_posted()
    assert fx["owner_manual_input_count"] == 0
    assert fx["owner_manual_gemini_review_comment_count"] == 0
    assert fx["evidence_source"]["owner_manual_input_count"] == 0
    # BOT 계정 /gemini review 시도도 0 (회장 §명시 금지 #4).
    assert fx["evidence_source"]["bot_gemini_review_attempt_count"] == 0


def test_downstream_gemini_fresh_and_bot_squash_merge():
    """downstream evidence — Gemini fresh 도착 + BOT squash merge 완결 박제."""
    fx = _load_posted()
    downstream = fx["downstream"]
    assert downstream["gemini_review_id"] == 4271590810
    assert downstream["gemini_review_commit_id"] == EXPECTED_HEAD
    assert downstream["gemini_review_state"] == "COMMENTED"
    assert downstream["ci_11_checks_status"] == "SUCCESS"
    assert downstream["merge_state_status"] == "CLEAN"
    assert downstream["merged_by"] == "app/jeon-jonghyuk-taskctl-bot"
    assert downstream["merge_commit"] == "696ab9c8b15ff135e1e358130ec118316f7fbc6d"


# ─── tests — cross-fixture (fixture 3 페어) ────────────────────────────────────


def test_cross_fixture_token_hash_unchanged_from_attempt_4_to_5():
    """fixture 2 + fixture 3 cross-check — token_hash_prefix 변경 0 (regenerate 없이 권한만 추가)."""
    posted = _load_posted()
    pair = _load_pair()

    # fixture 2 (POSTED) 내부 어셀션.
    assert posted["prior_attempt_hash_prefix"] == posted["token_hash_prefix"]
    assert posted["token_hash_changed_from_attempt_4"] is False
    assert posted["token_regenerate_occurred"] is False

    # fixture 3 (페어) cross-check.
    assert pair["schema"] == EXPECTED_PAIR_SCHEMA
    assert pair["token_hash_unchanged"] is True
    assert pair["token_hash_prefix_before"] == pair["token_hash_prefix_after"]
    assert pair["token_hash_prefix_before"] == EXPECTED_TOKEN_HASH_PREFIX
    assert pair["token_regenerate_occurred"] is False

    # 두 fixture 가 동일 token 으로 attempt 페어를 1:1 박제.
    assert pair["attempt_4"]["token_hash_prefix"] == pair["attempt_5"]["token_hash_prefix"]
    assert pair["attempt_5"]["token_hash_prefix"] == posted["token_hash_prefix"]


def test_pair_fixture_permission_added_pull_requests_write_only():
    """fixture 3 — permission_added == [pull_requests=write] 1 건 박제."""
    pair = _load_pair()
    assert pair["permission_added"] == ["pull_requests=write"]
    assert len(pair["permission_added"]) == 1
    assert pair["permission_method"] == "github_owner_ui_token_edit"


def test_pair_fixture_outcome_transition_failed_to_posted():
    """fixture 3 — outcome transition FAILED→POSTED 박제."""
    pair = _load_pair()
    assert pair["attempt_4"]["result"] == "FAILED"
    assert pair["attempt_4"]["http_status"] == 403
    assert pair["attempt_4"]["classification"] == "TOKEN_SCOPE_MISMATCH_DIAGNOSED"
    assert pair["attempt_5"]["result"] == "POSTED"
    assert pair["attempt_5"]["http_status"] == 201
    assert pair["expected_pair_assertion"]["outcome_transition"] == "FAILED→POSTED"
    assert pair["expected_pair_assertion"]["owner_manual_gemini_review_comment_count"] == 0


def test_pair_fixture_attempt5_comment_metadata_matches_posted_fixture():
    """fixture 2 ↔ fixture 3 — attempt_5 comment metadata 가 cross-fixture 일치."""
    posted = _load_posted()
    pair = _load_pair()
    a5 = pair["attempt_5"]
    assert a5["comment_id"] == posted["comment_id"]
    assert a5["comment_user_login"] == posted["comment_user_login"]
    assert a5["comment_html_url"] == posted["comment_html_url"]
    assert a5["comment_author_association"] == posted["comment_author_association"]


@pytest.mark.parametrize(
    "field",
    [
        "schema",
        "task_id",
        "attempt",
        "pr",
        "head",
        "ts",
        "endpoint",
        "method",
        "http_status",
        "comment_body",
        "comment_id",
        "comment_user_login",
        "comment_html_url",
        "comment_author_association",
        "token_present",
        "token_hash_prefix",
        "token_value_logged",
        "prior_attempt_hash_prefix",
        "prior_attempt_index",
        "prior_attempt_ts",
        "token_hash_changed_from_attempt_4",
        "permission_added_between_attempts",
        "token_regenerate_occurred",
        "capability_first_practical_use",
        "owner_manual_input_count",
        "owner_manual_gemini_review_comment_count",
        "evidence_source",
        "downstream",
        "lesson_pinned",
    ],
)
def test_owner_trigger_posted_v1_required_fields_present(field):
    """schema owner-trigger-posted.v1 필수 필드 누락 회귀 catch."""
    fx = _load_posted()
    assert field in fx, f"required field missing in owner-trigger-posted.v1 fixture: {field}"


@pytest.mark.parametrize(
    "field",
    [
        "schema",
        "task_id",
        "pr",
        "head",
        "endpoint",
        "attempt_4",
        "attempt_5",
        "token_hash_unchanged",
        "token_hash_prefix_before",
        "token_hash_prefix_after",
        "permission_added",
        "permission_method",
        "token_regenerate_occurred",
        "elapsed_seconds_between_attempts",
        "expected_pair_assertion",
        "lesson_pinned",
    ],
)
def test_permission_update_no_regen_v1_required_fields_present(field):
    """schema permission-update-no-regen.v1 필수 필드 누락 회귀 catch."""
    pair = _load_pair()
    assert field in pair, f"required field missing in permission-update-no-regen.v1 fixture: {field}"
