from __future__ import annotations

import argparse
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from src.research.tradingview_context import load_tradingview_latest, rank_tradeable_coins, context_to_journal_dict

DEFAULT_CANDIDATES = ["BTC", "ETH", "SOL", "LINK", "WLD", "SUI", "ENA", "BCH"]


def _read_jsonl(path: Path) -> list[dict[str, Any]]:
    if not path.exists():
        return []
    rows: list[dict[str, Any]] = []
    for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
        if not line.strip():
            continue
        try:
            row = json.loads(line)
        except json.JSONDecodeError:
            continue
        if isinstance(row, dict):
            rows.append(row)
    return rows


def _paper_pnl_by_coin(runtime_root: Path) -> dict[str, float]:
    out: dict[str, float] = {}
    for path in runtime_root.glob("*/trade_journal.jsonl"):
        for row in _read_jsonl(path):
            if str(row.get("event") or "").lower() != "exit":
                continue
            coin = str(row.get("coin") or "").upper()
            if not coin:
                continue
            try:
                pnl = float(row.get("net_pnl_usd", row.get("realized_pnl_usd", 0)) or 0)
            except (TypeError, ValueError):
                continue
            out[coin] = out.get(coin, 0.0) + pnl
    shadow = runtime_root / "trader_desk_shadow" / "outcome_journal.jsonl"
    for row in _read_jsonl(shadow):
        coin = str(row.get("coin") or "").upper()
        if not coin:
            continue
        try:
            pnl = float(row.get("realized_r", row.get("r_multiple", 0)) or 0)
        except (TypeError, ValueError):
            continue
        out[coin] = out.get(coin, 0.0) + pnl
    return out


def build_selection_report(*, candidates: list[str], runtime_root: Path, tv_path: Path) -> dict[str, Any]:
    contexts = load_tradingview_latest(tv_path)
    pnl = _paper_pnl_by_coin(runtime_root)
    ranked = rank_tradeable_coins(candidate_coins=candidates, paper_pnl_by_coin=pnl, tv_contexts=contexts)
    return {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "research_only": True,
        "live_order_allowed": False,
        "mainnet_signed_action": False,
        "input_candidates": candidates,
        "selected_order": ranked,
        "paper_shadow_pnl_by_coin": {coin: round(pnl.get(coin, 0.0), 8) for coin in candidates},
        "tradingview_context": {coin: context_to_journal_dict(contexts.get(coin)) for coin in candidates},
        "selection_policy": "measured_paper_shadow_evidence_first_then_tradingview_context_quality",
    }


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description="Rank tradeable coins using paper/shadow evidence plus TradingView MCP context.")
    parser.add_argument("--runtime-root", default="runtime/experiments")
    parser.add_argument("--tv-context", default="runtime/research/tradingview_latest.json")
    parser.add_argument("--output", default="runtime/research/tradeable_coin_selection_latest.json")
    parser.add_argument("--coins", default=",".join(DEFAULT_CANDIDATES))
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args(argv)
    candidates = [c.strip().upper() for c in args.coins.split(",") if c.strip()]
    payload = build_selection_report(candidates=candidates, runtime_root=Path(args.runtime_root), tv_path=Path(args.tv_context))
    out = Path(args.output)
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_text(json.dumps(payload, indent=2, sort_keys=True), encoding="utf-8")
    print(json.dumps(payload, indent=2, sort_keys=True) if args.json else f"wrote {out}")
    return 0


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