#!/usr/bin/env python3
"""
NEXT Athlete OS - RC44 physio review patch applier.

Consumes rc44_physio_review_patch.json exported from tools/physio_motion_blueprint_lab.html
and creates a reviewed sequence proposal. It does not overwrite active runtime sequences
unless --activate is explicitly provided.
"""
from __future__ import annotations

import argparse
import datetime as dt
import json
import shutil
from pathlib import Path
from typing import Any, Dict

ROOT = Path(__file__).resolve().parents[1]
DEFAULT_SEQUENCES = ROOT / "assets/data/image-admin/pose-atlas-exercise-sequences.json"
DEFAULT_REPORT = ROOT / "assets/data/image-admin/rc44_physio_candidate_match_report.json"
DEFAULT_OUT = ROOT / "assets/data/image-admin/pose-atlas-exercise-sequences.rc44-physio-reviewed-proposal.json"


def now_iso() -> str:
    return dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat()


def read_json(path: Path) -> Any:
    return json.loads(path.read_text(encoding="utf-8"))


def write_json(path: Path, data: Any) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")


def build_lookup(report: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
    out = {}
    for ex_key, ex in (report.get("exercises") or {}).items():
        for kf in ex.get("keyframes") or []:
            out[f"{ex_key}/{kf.get('keyframeId')}"] = kf
    return out


def main() -> None:
    ap = argparse.ArgumentParser()
    ap.add_argument("--patch", type=Path, required=True, help="rc44_physio_review_patch.json exported from the browser lab")
    ap.add_argument("--sequences", type=Path, default=DEFAULT_SEQUENCES)
    ap.add_argument("--report", type=Path, default=DEFAULT_REPORT)
    ap.add_argument("--out", type=Path, default=DEFAULT_OUT)
    ap.add_argument("--activate", action="store_true", help="overwrite pose-atlas-exercise-sequences.json after writing a backup")
    args = ap.parse_args()

    seqs = read_json(args.sequences)
    patch = read_json(args.patch)
    report = read_json(args.report)
    decisions = patch.get("decisions") or {}
    lookup = build_lookup(report)

    proposal = json.loads(json.dumps(seqs))
    proposal["version"] = "v97-rc44-physio-reviewed-proposal"
    proposal["intent"] = "Physio-reviewed pose sequence proposal generated from RC44 review patch. Review before activation."
    proposal["rc44Review"] = {
        "createdAt": now_iso(),
        "patchSchema": patch.get("schema"),
        "sourceTool": patch.get("sourceTool"),
        "activatedRuntime": bool(args.activate),
        "decisionCount": len(decisions),
    }

    applied = []
    skipped = []
    for key, decision in decisions.items():
        ex_key, _, kf_id = key.partition('/')
        if not ex_key or not kf_id:
            skipped.append({"key": key, "reason": "bad-key"})
            continue
        selected = decision.get("selectedCandidate") or {}
        status = decision.get("decision") or "unset"
        if status not in ("approved", "special-handling") or not selected.get("poseKey"):
            skipped.append({"key": key, "reason": "not-approved-or-no-selected-candidate", "decision": status})
            continue
        seq = (proposal.get("sequences") or {}).get(ex_key)
        if not seq:
            skipped.append({"key": key, "reason": "missing-exercise"})
            continue
        poses = seq.get("poses") or []
        target_index = None
        for i, step in enumerate(poses):
            if f"{ex_key}__kf{i+1:02d}" == kf_id:
                target_index = i
                break
        if target_index is None:
            skipped.append({"key": key, "reason": "missing-keyframe-index"})
            continue
        poses[target_index]["poseKey"] = selected["poseKey"]
        poses[target_index]["athleteOverride"] = selected.get("athleteId")
        poses[target_index]["rc44PhysioReview"] = {
            "decision": status,
            "score": selected.get("score"),
            "cue": decision.get("cue"),
            "notes": decision.get("notes"),
            "reviewPatchKey": key,
            "source": "rc44-physio-review-patch",
        }
        applied.append({"key": key, "poseKey": selected.get("poseKey"), "athleteId": selected.get("athleteId"), "decision": status})

    proposal["rc44Review"]["applied"] = applied
    proposal["rc44Review"]["skipped"] = skipped
    write_json(args.out, proposal)

    if args.activate:
        backup = args.sequences.with_suffix(".rc43-before-rc44-physio-activation.backup.json")
        shutil.copy2(args.sequences, backup)
        write_json(args.sequences, proposal)

    print(json.dumps({
        "version": proposal["version"],
        "applied": len(applied),
        "skipped": len(skipped),
        "out": str(args.out.relative_to(ROOT) if args.out.is_relative_to(ROOT) else args.out),
        "activatedRuntime": bool(args.activate),
    }, indent=2, ensure_ascii=False))

if __name__ == "__main__":
    main()
