# -*- coding: utf-8 -*-
"""regression — task-2553+57 Track B NEXT_RUNTIME_STRUCTURE_PILOT_PLAN.

스키마/조건 검증 + mock-only FAIL 음성 케이스. 실 policy_profile_engine
read-only resolve 실 entrypoint 가 호출됨을 *증명* 한다 (문서-only/날조
완료 금지). 본 테스트는 read-only — write 0, 실 dispatch 0.
"""
from __future__ import annotations

import importlib.util
import sys
from pathlib import Path

import pytest

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


@pytest.fixture(scope="module")
def builder():
    # scripts/ 는 패키지가 아니므로 파일 경로로 로딩 (sibling +51 테스트와 동일).
    spec = importlib.util.spec_from_file_location(
        "_p57_builder", ROOT / "scripts/build_next_pilot_plan_2553plus57.py"
    )
    assert spec and spec.loader
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


def test_expected_files_allowlist_exact(builder):
    """§3 expected_files allowlist = 정확히 9종, Track A/C/D disjoint 의도."""
    assert builder.EXPECTED_FILES == (
        "memory/events/pilot_goal.json",
        "memory/events/selected_policy_profile.json",
        "memory/events/pilot_execution_plan.json",
        "memory/events/success_criteria.json",
        "scripts/build_next_pilot_plan_2553plus57.py",
        "tests/regression/test_next_pilot_plan_2553plus57.py",
        "memory/events/task-2553+57.decision.json",
        "memory/events/task-2553+57.result.json",
        "memory/reports/task-2553+57.md",
    )
    # builder 가 정적 스크립트/테스트/리포트는 덮어쓰지 않음 (byte-0).
    for rel in builder.EMIT_FILES:
        assert rel in builder.EXPECTED_FILES
    assert "scripts/build_next_pilot_plan_2553plus57.py" not in builder.EMIT_FILES
    assert "tests/regression/test_next_pilot_plan_2553plus57.py" not in builder.EMIT_FILES
    assert "memory/reports/task-2553+57.md" not in builder.EMIT_FILES


def test_callback_owner_is_independent_anu_key(builder):
    """callback owner = 독립 ANU key; executor self key 절대 금지 (+49 정본)."""
    assert builder.ANU_CALLBACK_KEY == "c119085addb0f8b7"
    assert builder.EXECUTOR_SELF_KEY == "1e41a2324a3ccdd0"
    assert builder.ANU_CALLBACK_KEY != builder.EXECUTOR_SELF_KEY


def test_mock_only_path_fails(builder):
    """mock-only 검증 경로는 FAIL — 문서-only/날조 완료 금지 (§3/§5)."""
    with pytest.raises(builder.MockOnlyError):
        builder._call_real_entrypoints(allow_mock=True)


def test_real_entrypoint_resolves_readonly(builder):
    """실 policy_profile_engine read-only resolve 실 entrypoint 가
    runtime_structure_smoke_pilot 을 RESOLVED 로 산출 (mock 아님)."""
    real = builder._call_real_entrypoints(allow_mock=False)
    assert real["mock_only"] is False
    assert real["real_entrypoint"] is True
    assert "policy_profile_engine" in real["engine_consumed_read_only"]
    res = real["resolved"]
    assert res["status"] == "RESOLVED"
    assert res["profile_bound"] is True
    assert res["resolved_profile_name"] == "runtime_structure_smoke_pilot"
    # fail-closed 음성: 미매핑 goal_type 은 RESOLVED 아님.
    assert real["unknown_goal_type_resolution"]["status"] != "RESOLVED"
    # owner/key 일관성 (+49 코드 정본).
    okc = real["owner_key_consistency"]
    assert okc["mandated_is_anu_key"] is True
    assert okc["executor_self_is_anu_key"] is False


def test_build_all_artifacts_schema(builder):
    """4종 plan + decision/result 스키마/조건 검증, actual_dispatch=False."""
    built = builder.build_all()
    assert built.pop("__checks_passed__") is True
    pg = built["memory/events/pilot_goal.json"]
    assert pg["schema"].endswith("pilot_goal.v1")
    assert pg["actual_dispatch"] is False and pg["design_only"] is True
    assert pg["pilot_goal"]["goal_request"]["goal_type"] == "runtime_structure_smoke_pilot"

    sp = built["memory/events/selected_policy_profile.json"]
    assert sp["selected_profile"]["status"] == "RESOLVED"
    assert sp["engine_mapping_status"]["profile_engine_resolved"] is True
    assert sp["fail_closed_negative_check"]["expected_not_resolved"] is True

    pep = built["memory/events/pilot_execution_plan.json"]
    assert pep["actual_dispatch"] is False
    assert pep["conditions_2"]["no_branch_commit_push"] is True
    assert (
        pep["would_be_dispatch_contract_DESIGN_ONLY"][
            "normal_completion_callback_owner_key"
        ]
        == builder.ANU_CALLBACK_KEY
    )

    sc = built["memory/events/success_criteria.json"]
    ids = {c["id"] for c in sc["pilot_success_criteria"]}
    assert {"SC1_real_entrypoint", "SC5_callback_owner_anu_key", "SC8_no_actual_dispatch"} <= ids
    tcfac = sc["track_c_fallback_acceptance_criterion"]
    assert "task-2553+58" in tcfac["source"]
    joined = " ".join(tcfac["criterion"])
    assert "fallback ≠ progress" in joined or "진행/수락 트리거로 사용해서는 안" in joined
    assert "DUPLICATE_CALLBACK_IGNORED" in joined
    assert "normal-callback durable-success event" in joined

    dec = built["memory/events/task-2553+57.decision.json"]
    assert dec["actual_dispatch"] is False and dec["hold_for_chair"] is False

    rslt = built["memory/events/task-2553+57.result.json"]
    assert rslt["mock_only"] is False and rslt["real_entrypoint_called"] is True
    assert rslt["self_chain_authoritative"] is False
    assert rslt["actual_dispatch"] is False
    assert builder.ANU_CALLBACK_KEY in rslt["next_action"]


def test_no_self_star_and_no_actual_dispatch(builder):
    """self-* 0 · 실 dispatch 0 명시 (회장 §2/§4/§5)."""
    dec = builder.build_decision()
    assert "self-collector" in dec["self_star_zero"]
    assert dec["actual_dispatch"] is False
    pep = builder.build_pilot_execution_plan()
    assert "self-dispatch" in pep["would_be_dispatch_contract_DESIGN_ONLY"]["no_self_star"]
