from __future__ import annotations

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


def main() -> None:
    args = _parse_args()
    current = _read_json(args.current_report)
    candidate = _read_json(args.candidate_report)
    decision = _decision(
        current,
        candidate,
        min_trades=args.min_trades,
        min_profit_factor=args.min_profit_factor,
        min_avg_net_percent=args.min_avg_net_percent,
        max_score_regression=args.max_score_regression,
    )
    payload = {
        "accepted": decision["accepted"],
        "reason": decision["reason"],
        "current": _summary(current),
        "candidate": _summary(candidate),
    }
    if args.report:
        Path(args.report).write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(json.dumps(payload, ensure_ascii=False, sort_keys=True))
    if not decision["accepted"]:
        raise SystemExit(2)
    target = Path(args.target_artifact)
    candidate_artifact = Path(args.candidate_artifact)
    target.parent.mkdir(parents=True, exist_ok=True)
    shutil.copy2(candidate_artifact, target)


def _parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Accept or reject a retrained Torch candidate artifact.")
    parser.add_argument("--current-report", required=True)
    parser.add_argument("--candidate-report", required=True)
    parser.add_argument("--candidate-artifact", required=True)
    parser.add_argument("--target-artifact", required=True)
    parser.add_argument("--report", default="")
    parser.add_argument("--min-trades", type=int, default=8)
    parser.add_argument("--min-profit-factor", type=float, default=1.05)
    parser.add_argument("--min-avg-net-percent", type=float, default=0.0)
    parser.add_argument("--max-score-regression", type=float, default=0.05)
    return parser.parse_args()


def _decision(
    current: dict[str, Any],
    candidate: dict[str, Any],
    *,
    min_trades: int,
    min_profit_factor: float,
    min_avg_net_percent: float,
    max_score_regression: float,
) -> dict[str, Any]:
    candidate_score = _score(candidate)
    current_score = _score(current)
    candidate_replay = candidate.get("full_replay") if isinstance(candidate.get("full_replay"), dict) else {}
    candidate_walk = candidate.get("walk_forward") if isinstance(candidate.get("walk_forward"), dict) else {}
    walk_summary = candidate_walk.get("summary") if isinstance(candidate_walk.get("summary"), dict) else {}
    if not _validation_passed(candidate):
        return {"accepted": False, "reason": "candidate_failed_honest_validation"}
    if int(candidate_replay.get("trades", 0) or 0) < min_trades:
        return {"accepted": False, "reason": "candidate_has_too_few_full_replay_trades"}
    if float(candidate_replay.get("profit_factor", 0.0) or 0.0) < min_profit_factor:
        return {"accepted": False, "reason": "candidate_profit_factor_below_min"}
    if float(candidate_replay.get("avg_net_percent", 0.0) or 0.0) <= min_avg_net_percent:
        return {"accepted": False, "reason": "candidate_expectancy_non_positive"}
    if int(walk_summary.get("trades", 0) or 0) >= min_trades and float(walk_summary.get("avg_net_percent", 0.0) or 0.0) <= min_avg_net_percent:
        return {"accepted": False, "reason": "candidate_walk_forward_expectancy_non_positive"}
    if _validation_passed(current) and current_score > 0 and candidate_score < current_score * (1.0 - max_score_regression):
        return {"accepted": False, "reason": "candidate_score_regressed_vs_current"}
    return {"accepted": True, "reason": "candidate_passed_guard"}


def _validation_passed(report: dict[str, Any]) -> bool:
    validation = report.get("validation")
    if not isinstance(validation, dict):
        return False
    if "passed" in validation:
        return bool(validation.get("passed"))
    return str(validation.get("status", "")).strip().lower() in {"pass", "passed", "ok"}


def _score(report: dict[str, Any]) -> float:
    replay = report.get("full_replay") if isinstance(report.get("full_replay"), dict) else {}
    recommended = report.get("recommended") if isinstance(report.get("recommended"), dict) else {}
    replay_score = (
        float(replay.get("avg_net_percent", 0.0) or 0.0)
        + float(replay.get("total_net_percent", 0.0) or 0.0) * 0.02
        - float(replay.get("max_drawdown_percent", 0.0) or 0.0) * 0.05
        + min(float(replay.get("profit_factor", 0.0) or 0.0), 10.0) * 0.03
    )
    return replay_score + float(recommended.get("score", 0.0) or 0.0) * 0.25


def _summary(report: dict[str, Any]) -> dict[str, Any]:
    return {
        "score": round(_score(report), 6),
        "recommended": report.get("recommended", {}),
        "full_replay": report.get("full_replay", {}),
        "walk_forward_summary": (report.get("walk_forward") or {}).get("summary", {})
        if isinstance(report.get("walk_forward"), dict)
        else {},
        "benchmark_summary": (report.get("benchmark") or {}).get("summary", {})
        if isinstance(report.get("benchmark"), dict)
        else {},
        "validation": report.get("validation", {}),
    }


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


if __name__ == "__main__":
    main()
