"""run_release_ci_gate_v2.py — RELEASE_CI_GATE_V2

P1-024: 100% 완료 정의를 코드로 강제하는 CI 게이트.
schema → source_recheck → formula_coverage → golden → pass100 → execution_precedence
→ outcome_readiness → LLM_freedom 순서로 순차 검증.
하나라도 FAIL이면 release_ci_gate=BLOCK_DEPLOYMENT.
"""
from __future__ import annotations

import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from v7_hardening_common import ROOT, TEMP, load_json, save_json

DEFAULT_OUT = TEMP / "release_ci_gate_v2.json"


def _f(v: Any, default: float = 0.0) -> float:
    try:
        return float(v)
    except Exception:
        return default


def _check(step: str, condition: bool, actual: Any, target: str, source: str) -> dict[str, Any]:
    return {
        "step": step,
        "status": "PASS" if condition else "FAIL",
        "actual": actual,
        "target": target,
        "source": source,
    }


def main() -> int:
    checks: list[dict[str, Any]] = []

    # ── Step 1: Schema Validity ──────────────────────────────────────────────
    dq = load_json(TEMP / "data_quality_reconciliation_v1.json")
    schema_score = _f(dq.get("schema_presence_score"))
    checks.append(_check(
        "1_SCHEMA_VALIDITY",
        schema_score >= 99.0,
        schema_score,
        ">= 99",
        "data_quality_reconciliation_v1.json",
    ))

    # ── Step 2: Source Recheck (Single Truth) ────────────────────────────────
    stl = load_json(TEMP / "single_truth_ledger_v2.json")
    conflict = int(stl.get("conflict_count") or 0)
    checks.append(_check(
        "2_SOURCE_RECHECK",
        conflict == 0,
        conflict,
        "== 0",
        "single_truth_ledger_v2.json",
    ))

    # ── Step 3: Formula Coverage ─────────────────────────────────────────────
    cov = load_json(TEMP / "harness_coverage_audit.json")
    true_missing = int(cov.get("true_missing_count") or 0)
    checks.append(_check(
        "3_FORMULA_COVERAGE",
        true_missing == 0,
        true_missing,
        "== 0",
        "harness_coverage_audit.json",
    ))

    # ── Step 4: Golden Test ──────────────────────────────────────────────────
    golden = load_json(TEMP / "formula_behavioral_coverage_v3.json")
    golden_fail = int(golden.get("failed_cases") or 0)
    checks.append(_check(
        "4_GOLDEN_TEST",
        golden_fail == 0,
        golden_fail,
        "failed_cases == 0",
        "formula_behavioral_coverage_v3.json",
    ))

    # ── Step 5: PASS_100 Active (v3) ─────────────────────────────────────────
    p100 = load_json(TEMP / "pass_100_criteria_v3.json")
    is_active = bool(p100.get("is_active"))
    checks.append(_check(
        "5_PASS_100_ACTIVE",
        is_active,
        is_active,
        "is_active == True",
        "pass_100_criteria_v3.json",
    ))

    # ── Step 6: Execution Precedence ─────────────────────────────────────────
    v4 = load_json(TEMP / "final_execution_decision_v4.json")
    audit_hts = str(v4.get("global_execution_gate") or "") == "AUDIT_ONLY" and int(v4.get("hts_order_count") or 0) == 0
    hts_ready = str(v4.get("global_execution_gate") or "") == "HTS_READY" and int(v4.get("hts_order_count") or 0) > 0
    precedence_ok = audit_hts or hts_ready
    checks.append(_check(
        "6_EXECUTION_PRECEDENCE",
        precedence_ok,
        f"gate={v4.get('global_execution_gate')},hts={v4.get('hts_order_count')}",
        "AUDIT_ONLY→hts=0 OR HTS_READY→hts>0",
        "final_execution_decision_v4.json",
    ))

    # ── Step 7: Outcome Readiness (honest) ───────────────────────────────────
    truth = load_json(TEMP / "operational_truth_score_v1.json")
    truth_gate = str(truth.get("gate") or "")
    # readiness is expected to be WATCH_PENDING_SAMPLE until T+20 accumulates — not a hard block
    readiness_ok = truth_gate != "BLOCK_EXECUTION"
    checks.append(_check(
        "7_OUTCOME_READINESS",
        readiness_ok,
        truth_gate,
        "!= BLOCK_EXECUTION (WATCH acceptable)",
        "operational_truth_score_v1.json",
    ))

    # ── Step 8: LLM Freedom ──────────────────────────────────────────────────
    honesty = load_json(TEMP / "truthfulness_guard_v1.json")
    violations = int(honesty.get("contradiction_count") or 0)
    checks.append(_check(
        "8_LLM_FREEDOM",
        violations == 0,
        violations,
        "contradiction_count == 0",
        "truthfulness_guard_v1.json",
    ))

    # ── 결과 집계 ────────────────────────────────────────────────────────────
    failed = [c for c in checks if c["status"] == "FAIL"]
    gate = "PASS" if not failed else "BLOCK_DEPLOYMENT"

    result = {
        "formula_id": "RELEASE_CI_GATE_V2",
        "gate": gate,
        "checks_total": len(checks),
        "checks_passed": len(checks) - len(failed),
        "checks_failed": len(failed),
        "failed_steps": [c["step"] for c in failed],
        "deploy_allowed": gate == "PASS",
        "checks": checks,
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "source_path": "Temp/release_ci_gate_v2.json",
    }
    save_json(str(DEFAULT_OUT), result)
    summary = {k: v for k, v in result.items() if k != "checks"}
    print(json.dumps(summary, indent=2, ensure_ascii=True))
    if gate == "PASS":
        print("RELEASE_CI_GATE_V2_PASS")
    else:
        print(f"RELEASE_CI_GATE_V2_BLOCK_DEPLOYMENT ({len(failed)} checks failed)")
        for c in failed:
            print(f"  FAIL {c['step']}: actual={c['actual']} target={c['target']}")
    return 0 if gate == "PASS" else 1


if __name__ == "__main__":
    raise SystemExit(main())
