from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any


ROOT = Path(__file__).resolve().parents[1]
DEFAULT_TRUTH = ROOT / "Temp" / "operational_truth_score_v1.json"
DEFAULT_DECISION = ROOT / "Temp" / "final_execution_decision_v1.json"
DEFAULT_MATRIX = ROOT / "Temp" / "execution_readiness_matrix_v1.json"
DEFAULT_DQ = ROOT / "Temp" / "data_quality_reconciliation_v1.json"
DEFAULT_SCR = ROOT / "Temp" / "smart_cash_recovery_v5.json"
DEFAULT_HARDENING = ROOT / "Temp" / "strategy_hardening_harness_v2.json"
DEFAULT_OUT = ROOT / "Temp" / "pass_100_criteria_v1.json"


def _load(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {}
    try:
        obj = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}
    return obj if isinstance(obj, dict) else {}


def _as_float(value: Any, default: float = 0.0) -> float:
    try:
        if value is None or value == "":
            return default
        return float(value)
    except Exception:
        return default


def _criterion(criterion_id: str, actual: Any, target: str, passed: bool, source_json: str, formula_id: str, remediation: str) -> dict[str, Any]:
    return {
        "criterion_id": criterion_id,
        "actual": actual,
        "target": target,
        "passed": bool(passed),
        "source_json": source_json,
        "formula_id": formula_id,
        "remediation": "NONE" if passed else remediation,
    }


def main() -> int:
    ap = argparse.ArgumentParser(description="Build PASS_100_CRITERIA_V1.")
    ap.add_argument("--truth", default=str(DEFAULT_TRUTH))
    ap.add_argument("--decision", default=str(DEFAULT_DECISION))
    ap.add_argument("--matrix", default=str(DEFAULT_MATRIX))
    ap.add_argument("--dq", default=str(DEFAULT_DQ))
    ap.add_argument("--scr", default=str(DEFAULT_SCR))
    ap.add_argument("--hardening", default=str(DEFAULT_HARDENING))
    ap.add_argument("--out", default=str(DEFAULT_OUT))
    args = ap.parse_args()

    def _rp(path_str: str) -> Path:
        path = Path(path_str)
        return path if path.is_absolute() else ROOT / path

    truth = _load(_rp(args.truth))
    decision = _load(_rp(args.decision))
    matrix = _load(_rp(args.matrix))
    dq = _load(_rp(args.dq))
    scr = _load(_rp(args.scr))
    hardening = _load(_rp(args.hardening))

    domain_scores = hardening.get("domain_scores") if isinstance(hardening.get("domain_scores"), dict) else {}
    meta_scores = hardening.get("meta_scores") if isinstance(hardening.get("meta_scores"), dict) else {}
    basis = truth.get("metric_basis") if isinstance(truth.get("metric_basis"), dict) else {}
    decision_basis = decision.get("decision_basis") if isinstance(decision.get("decision_basis"), dict) else {}

    schema_score = _as_float(dq.get("schema_presence_score", basis.get("schema_presence_score")))
    formula_coverage = _as_float(domain_scores.get("formula_runtime_coverage_pct", basis.get("formula_runtime_coverage_pct", 100.0)))
    cap_basis = _as_float(dq.get("confidence_cap_basis_score", basis.get("confidence_cap_basis_score")))
    truth_score = _as_float(truth.get("score_0_100"))
    execution_score = _as_float(truth.get("execution_truth_score"))
    performance_score = _as_float(truth.get("performance_readiness_score"))
    scr_damage = _as_float(scr.get("value_damage_pct_avg"))
    hts_count = int(_as_float(decision.get("hts_order_count")))
    export_status = str(decision_basis.get("export_status") or basis.get("export_status") or "UNKNOWN")
    export_allowed = decision_basis.get("export_allowed")
    readiness_gate = str(meta_scores.get("readiness_gate") or decision_basis.get("readiness_gate") or "MISSING")
    matrix_gate = str(matrix.get("gate") or "MISSING")
    matrix_min = _as_float(matrix.get("min_axis_score"))

    criteria = [
        _criterion("SCHEMA_PRESENCE_100", schema_score, "== 100", schema_score == 100.0, "data_quality_reconciliation_v1.json", "DATA_QUALITY_RECONCILIATION_V1", "restore missing required JSON collections/fields"),
        _criterion("FORMULA_RUNTIME_COVERAGE_100", formula_coverage, "== 100", formula_coverage == 100.0, "strategy_hardening_harness_v2.json", "STRATEGY_HARDENING_HARNESS_V2", "map every YAML formula to runtime code and validator"),
        _criterion("CONFIDENCE_CAP_BASIS_GE_90", cap_basis, ">= 90", cap_basis >= 90.0, "data_quality_reconciliation_v1.json", "DATA_QUALITY_RECONCILIATION_V1", "fill actual investment-quality evidence; do not use schema score as substitute"),
        _criterion("OPERATIONAL_TRUTH_SCORE_100", truth_score, "== 100 and gate PASS_100", truth_score == 100.0 and str(truth.get("gate") or "") == "PASS_100", "operational_truth_score_v1.json", "OPERATIONAL_TRUTH_SCORE_V1", "remove all truth blockers and rerun truth score"),
        _criterion("EXECUTION_TRUTH_SCORE_100", execution_score, "== 100", execution_score == 100.0, "operational_truth_score_v1.json", "OPERATIONAL_TRUTH_SCORE_V1", "resolve export/order validation blockers"),
        _criterion("PERFORMANCE_READINESS_GE_90", performance_score, ">= 90 and readiness_gate PERFORMANCE_READY", performance_score >= 90.0 and readiness_gate == "PERFORMANCE_READY", "operational_truth_score_v1.json", "OPERATIONAL_TRUTH_SCORE_V1", "accumulate operating T+20 samples or complete performance replay audit"),
        _criterion("SMART_CASH_VALUE_DAMAGE_LE_10", scr_damage, "<= 10", scr_damage <= 10.0, "smart_cash_recovery_v5.json", "SMART_CASH_RECOVERY_V5", "rebuild rebound-preserving sell plan with value damage <= 10%"),
        _criterion("SMART_CASH_EXECUTION_ALLOWED", scr.get("execution_allowed"), "is true and status PASS", bool(scr.get("execution_allowed")) and str(scr.get("status") or "") == "PASS", "smart_cash_recovery_v5.json", "SMART_CASH_RECOVERY_V5", "clear smart cash recovery hard blocks"),
        _criterion("EXPORT_GATE_READY", {"status": export_status, "allowed": export_allowed}, "EXPORT_READY and allowed true", export_status == "EXPORT_READY" and export_allowed is True, "final_execution_decision_v1.json", "FINAL_EXECUTION_DECISION_V1", "rerun GAS export until export_gate_json.hts_entry_allowed=true"),
        _criterion("FINAL_EXECUTION_HTS_READY", decision.get("global_execution_gate"), "HTS_READY", str(decision.get("global_execution_gate") or "") == "HTS_READY", "final_execution_decision_v1.json", "FINAL_EXECUTION_DECISION_V1", "remove truth/export/readiness blockers before HTS order generation"),
        _criterion("HTS_ORDER_COUNT_GT_0", hts_count, "> 0", hts_count > 0, "final_execution_decision_v1.json", "FINAL_EXECUTION_DECISION_V1", "order_blueprint_json must contain PASS validation rows"),
        _criterion("EXECUTION_READINESS_MATRIX_PASS_100", {"gate": matrix_gate, "min_axis_score": matrix_min}, "gate PASS_100 and min_axis_score 100", matrix_gate == "PASS_100" and matrix_min == 100.0, "execution_readiness_matrix_v1.json", "EXECUTION_READINESS_MATRIX_V1", "raise every readiness axis to 100 or keep EXPLAIN_ONLY"),
    ]

    failed = [row for row in criteria if not row["passed"]]
    score = round((len(criteria) - len(failed)) / len(criteria) * 100.0, 2) if criteria else 0.0
    pass_allowed = len(failed) == 0
    gate = "PASS_100" if pass_allowed else "BLOCK_EXECUTION"

    result = {
        "formula_id": "PASS_100_CRITERIA_V1",
        "gate": gate,
        "pass_100_allowed": pass_allowed,
        "score_0_100": score,
        "passed_count": len(criteria) - len(failed),
        "failed_count": len(failed),
        "failed_criteria": [str(row["criterion_id"]) for row in failed],
        "criteria": criteria,
        "targets": {
            "completion_definition": "PASS_100 only when every criterion passed",
            "hts_execution_definition": "HTS execution remains forbidden unless FINAL_EXECUTION_HTS_READY and HTS_ORDER_COUNT_GT_0 pass",
            "llm_role": "copy criteria and render ledgers only; no ad-hoc numeric overrides",
        },
    }

    out_path = _rp(args.out)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
    print(json.dumps(result, ensure_ascii=False, indent=2))
    return 0


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