from __future__ import annotations

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


ROOT = Path(__file__).resolve().parents[1]
DEFAULT_JSON = ROOT / "GatherTradingData.json"
DEFAULT_OUT = ROOT / "Temp" / "decision_evidence_score_v2.json"


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


def _rows(v: Any) -> list[dict[str, Any]]:
    if isinstance(v, list):
        return [x for x in v if isinstance(x, dict)]
    if isinstance(v, str):
        try:
            return _rows(json.loads(v))
        except Exception:
            return []
    return []


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--json", default=str(DEFAULT_JSON))
    ap.add_argument("--out", default=str(DEFAULT_OUT))
    args = ap.parse_args()

    jp = Path(args.json)
    op = Path(args.out)
    if not jp.is_absolute():
        jp = ROOT / jp
    if not op.is_absolute():
        op = ROOT / op

    payload = _load(jp)
    h = {}
    if isinstance(payload.get("data"), dict) and isinstance(payload["data"].get("_harness_context"), dict):
        h.update(payload["data"]["_harness_context"])
    if isinstance(payload.get("hApex"), dict):
        h.update(payload["hApex"])

    bp = _rows(h.get("order_blueprint_json"))
    actionable = [r for r in bp if str(r.get("order_type") or "").upper() in {"BUY", "ADD_ON", "STAGED_BUY", "SELL", "STOP_LOSS", "TRIM"}]
    rationale_re = re.compile(r"([A-Z][A-Z0-9_]*_V[0-9]+|NO_EXECUTION:[A-Z_]+|EXPORT_GATE_[A-Z_]+)")
    rationale_total = 0
    rationale_ok = 0
    free_text_violation = 0
    numeric_source_cov = 100.0

    for row in actionable:
        rc = str(row.get("rationale_code") or "")
        if rc:
            rationale_total += 1
            if rationale_re.search(rc):
                rationale_ok += 1
            else:
                free_text_violation += 1
        for k in ("quantity", "limit_price_krw", "stop_price_krw", "take_profit_price_krw"):
            if k in row and row.get(k) not in (None, "") and "rationale_code" not in row:
                numeric_source_cov = 0.0

    if len(actionable) == 0:
        score = None
        score_state = "N_A_NO_ACTIONABLE_ORDERS"
        gate = "NO_ACTIONABLE_ORDERS_NEUTRAL"
    else:
        rq = 100.0 if rationale_total == 0 else (rationale_ok / max(1, rationale_total)) * 100.0
        score = round(max(0.0, min(100.0, rq * 0.7 + numeric_source_cov * 0.3)), 2)
        score_state = "SCORED"
        gate = "PASS" if score >= 92 else ("WARN" if score >= 80 else "FAIL")

    out = {
        "formula_id": "DECISION_EVIDENCE_SCORE_V2",
        "score": score,
        "score_state": score_state,
        "evidence_rows": len(bp),
        "rationale_rows": rationale_total,
        "numeric_source_coverage_pct": numeric_source_cov,
        "free_text_rationale_violation_count": free_text_violation,
        "gate": gate,
        "metrics": {
            "rationale_ok": rationale_ok,
            "actionable_rows": len(actionable)
        }
    }

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


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