"""Summarize ORB no-trade days from a saved intraday backtest JSON.

This intentionally works from the run artifact only. For new runs that include
entry_diagnostics, it also reports whether no-trade days had primary, no-fill,
or soft-day VWAP candidates that were later rejected by gates.
"""
from __future__ import annotations

import argparse
import json
from collections import Counter, defaultdict
from pathlib import Path
from typing import Any


def _fmt_float(value: Any, digits: int = 3) -> str:
    if value is None:
        return "-"
    try:
        return f"{float(value):.{digits}f}"
    except (TypeError, ValueError):
        return str(value)


def _reason_for(day: dict[str, Any]) -> str:
    if day.get("skip_reason"):
        return str(day["skip_reason"])
    if day.get("is_soft_day"):
        return "soft:" + str(day.get("soft_day_reason") or "scaler")
    if int(day.get("candidates_found") or 0) > 0:
        return "traded_no_fill"
    return "unknown_no_fill"


def summarize(path: Path, limit: int) -> None:
    payload = json.loads(path.read_text())
    days = payload.get("daily_summary", [])
    no_trade_days = [d for d in days if int(d.get("trades") or 0) == 0]
    by_reason: Counter[str] = Counter(_reason_for(d) for d in no_trade_days)

    print(f"Run: {payload.get('run_id', path.name)}")
    metrics = payload.get("metrics", {})
    print(
        "Period: "
        f"{metrics.get('start_date', '-')}"
        f" -> {metrics.get('end_date', '-')}"
        f" | trade_days={metrics.get('days_with_trades', '-')}"
        f"/{metrics.get('trading_days', len(days))}"
        f" | return={_fmt_float((metrics.get('total_return_pct') or 0) * 100, 2)}%"
        f" | dd={_fmt_float((metrics.get('max_drawdown_pct') or 0) * 100, 2)}%"
    )
    print()
    print("No-trade day breakdown:")
    for reason, count in by_reason.most_common():
        print(f"  {reason}: {count}")

    reject_totals: Counter[str] = Counter()
    candidate_counts: defaultdict[str, int] = defaultdict(int)
    for day in no_trade_days:
        diag = day.get("entry_diagnostics") or {}
        for key in (
            "primary_timed_candidates",
            "nofill_vwap_candidates",
            "soft_day_vwap_candidates",
            "timed_candidates",
        ):
            candidate_counts[key] += int(diag.get(key) or 0)
        reject_totals.update(diag.get("entry_reject_stats") or {})

    if candidate_counts:
        print()
        print("Entry candidate counts on no-trade days:")
        for key, value in candidate_counts.items():
            print(f"  {key}: {value}")
    if reject_totals:
        print()
        print("Entry rejection totals on no-trade days:")
        for reason, count in reject_totals.most_common():
            print(f"  {reason}: {count}")

    print()
    print(f"Recent/detail no-trade days (last {limit}):")
    for day in no_trade_days[-limit:]:
        diag = day.get("entry_diagnostics") or {}
        rejects = diag.get("entry_reject_stats") or {}
        reject_text = ",".join(f"{k}:{v}" for k, v in sorted(rejects.items())) or "-"
        print(
            "  "
            f"{day.get('date')}"
            f" | reason={_reason_for(day)}"
            f" | cands={day.get('candidates_found')}"
            f" | primary={diag.get('primary_timed_candidates', '-')}"
            f" | nofill_vwap={diag.get('nofill_vwap_candidates', '-')}"
            f" | soft_vwap={diag.get('soft_day_vwap_candidates', '-')}"
            f" | reg={_fmt_float(day.get('regime_scaler'))}"
            f" | breadth={_fmt_float(day.get('breadth_scaler'))}"
            f" | moq={_fmt_float(day.get('market_orb_quality_scaler'))}"
            f" | rejects={reject_text}"
        )


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("run_json", type=Path)
    parser.add_argument("--limit", type=int, default=30)
    args = parser.parse_args()
    summarize(args.run_json, args.limit)


if __name__ == "__main__":
    main()
