from __future__ import annotations

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

from lib_trading_calendar import next_trading_day


ROOT = Path(__file__).resolve().parents[1]
DEFAULT_HISTORY = ROOT / "Temp" / "proposal_evaluation_history.json"
DEFAULT_OUT = ROOT / "Temp" / "operational_eval_queue_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 _add_trading_days(start: date, n: int) -> date:
    cur = start
    for _ in range(max(0, n)):
        cur = next_trading_day(cur)
    return cur


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--history", default=str(DEFAULT_HISTORY))
    ap.add_argument("--out", default=str(DEFAULT_OUT))
    ap.add_argument("--t20-days", type=int, default=28)
    args = ap.parse_args()

    hp = Path(args.history)
    op = Path(args.out)
    if not hp.is_absolute():
        hp = ROOT / hp
    if not op.is_absolute():
        op = ROOT / op

    history = _load(hp)
    rows = history.get("records") if isinstance(history.get("records"), list) else []
    today = date.today()
    queue: list[dict[str, Any]] = []
    due_cnt = 0
    done_cnt = 0
    missing_due_dates = 0
    for r in rows:
        if not isinstance(r, dict):
            continue
        pd = str(r.get("proposal_date") or "")
        if not pd:
            missing_due_dates += 1
            continue
        try:
            d0 = date.fromisoformat(pd)
        except Exception:
            missing_due_dates += 1
            continue
        age = (today - d0).days
        due_t1 = _add_trading_days(d0, 1).isoformat()
        due_t5 = _add_trading_days(d0, 5).isoformat()
        due_t20 = _add_trading_days(d0, 20).isoformat()
        t20_status = str(r.get("t20_evaluation_status") or "")
        if t20_status == "EVALUATED_T20":
            done_cnt += 1
            continue
        if age >= args.t20_days:
            due_cnt += 1
            queue.append(
                {
                    "proposal_date": pd,
                    "due_date_t1": due_t1,
                    "due_date_t5": due_t5,
                    "due_date_t20": due_t20,
                    "ticker": r.get("ticker"),
                    "name": r.get("name"),
                    "strategy_action": r.get("strategy_action"),
                    "validation_status": r.get("validation_status"),
                    "age_days": age,
                    "next_action": "CAPTURE_T20_OUTCOME_REQUIRED",
                }
            )

    queue = sorted(queue, key=lambda x: int(x.get("age_days") or 0), reverse=True)
    out = {
        "formula_id": "OPERATIONAL_EVAL_QUEUE_V1",
        "as_of": today.isoformat(),
        "t20_days_threshold": int(args.t20_days),
        "metrics": {
            "records_total": len(rows),
            "t20_evaluated_count": done_cnt,
            "t20_due_capture_count": due_cnt,
            "missing_due_date_count": missing_due_dates,
        },
        "all_proposals_have_due_dates": missing_due_dates == 0 and len(rows) > 0,
        "queue": queue[:500],
        "todo_protocol": [
            "1) queue 상위 종목부터 T+20 실제 결과값 입력",
            "2) validation_status=REPLAY_BACKFILL는 운영성과로 집계 금지",
            "3) 입력 후 update-evaluation-history -> build-execution-quality-harness -> build-operational-outcome-lock-v1 재실행",
        ],
    }

    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())
