"""runners-01 — 셸 시나리오에서 꺼낸 단언 블록.

호출부: validators/lib/runners.sh:44
규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
"""
from pathlib import Path
import json
import subprocess
import sys

project_root = Path(sys.argv[1])
task_manifest_path = project_root / sys.argv[2]
validator_script = Path(sys.argv[3])
expected_status = sys.argv[4]
expected_failure_substring = sys.argv[5]

task_manifest = json.loads(task_manifest_path.read_text())
timeline_path = project_root / task_manifest["historyTimelinePath"]
timeline = json.loads(timeline_path.read_text())
runs = timeline.get("runs", [])
latest_run = None
if isinstance(runs, list):
    for item in reversed(runs):
        if isinstance(item, dict):
            latest_run = item
            break

if latest_run is None:
    raise SystemExit("timeline does not contain a latest run entry")

run_manifest_path = project_root / latest_run["runManifestPath"]
run_manifest = json.loads(run_manifest_path.read_text())
team_state_path = project_root / run_manifest["teamStatePath"]
report_path = project_root / run_manifest["expectedReportRecordPath"]
final_status_path = project_root / run_manifest["expectedStatusPath"]

process = subprocess.run(
    [
        sys.executable,
        str(validator_script),
        "--team-state",
        str(team_state_path),
        "--report",
        str(report_path),
        "--run-manifest",
        str(run_manifest_path),
        "--task-manifest",
        str(task_manifest_path),
        "--final-status",
        str(final_status_path),
        # session-conformance 주입 시드 — prepare_run_validator_fixture 가
        # 만든 합성 lead jsonl 디렉터리 (실제 ~/.claude/projects 미오염).
        "--claude-projects-dir",
        str(project_root / ".claude-projects-fixture"),
    ],
    capture_output=True,
    text=True,
)

if not process.stdout.strip():
    raise SystemExit("validator did not produce JSON output")

payload = json.loads(process.stdout)
actual_status = payload.get("validationStatus")
if actual_status != expected_status:
    extra = ""
    if expected_status == "passed":
        listed = payload.get("failures") or []
        extra = "\n" + "\n".join(str(item) for item in listed)
    raise SystemExit(
        f"validator status mismatch: expected {expected_status}, got {actual_status}{extra}"
    )

if expected_status == "passed" and process.returncode != 0:
    raise SystemExit(f"validator returned non-zero on success: {process.stderr}")
if expected_status == "failed" and process.returncode == 0:
    raise SystemExit("validator unexpectedly succeeded")

if expected_failure_substring:
    failures = payload.get("failures", [])
    if not isinstance(failures, list) or not any(
        expected_failure_substring in str(item) for item in failures
    ):
        raise SystemExit(
            f"validator failure output did not include expected text: {expected_failure_substring}"
        )

if not final_status_path.is_file():
    raise SystemExit(f"validator did not write final status file: {final_status_path}")

final_status = final_status_path.read_text().strip()
expected_final_status = "completed" if expected_status == "passed" else "contract-violated"
if final_status != expected_final_status:
    raise SystemExit(
        f"final status file mismatch: expected {expected_final_status}, got {final_status}"
    )

updated_run_manifest = json.loads(run_manifest_path.read_text())
updated_task_manifest = json.loads(task_manifest_path.read_text())
updated_team_state = json.loads(team_state_path.read_text())

if updated_run_manifest.get("validation", {}).get("status") != expected_status:
    raise SystemExit("run manifest validation status was not updated correctly")
if updated_task_manifest.get("contractValidation", {}).get("status") != expected_status:
    raise SystemExit("task manifest validation status was not updated correctly")
if updated_team_state.get("validator", {}).get("status") != expected_status:
    raise SystemExit("team-state validator status was not updated correctly")
