from __future__ import annotations

import argparse
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Sequence

from config import BotConfig, RuntimePaths
from strategy_lab import LabStrategy, default_research_sampler_strategies, run_strategy_lab, _load_candle_cache


def _append_jsonl(path: Path, row: dict) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("a", encoding="utf-8") as f:
        f.write(json.dumps(row, sort_keys=True, default=str) + "\n")


def _sampler_by_id(strategy_id: str) -> LabStrategy:
    for sampler in default_research_sampler_strategies():
        if sampler.strategy_id == strategy_id:
            return sampler
    known = ",".join(s.strategy_id for s in default_research_sampler_strategies())
    raise SystemExit(f"unknown sampler strategy_id={strategy_id}; known={known}")


def run_sampler(
    *,
    strategy_id: str,
    coins: Sequence[str],
    interval: str,
    hours_back: int,
    iterations: int,
    interval_seconds: float,
    runtime_dir: Path,
    json_output: bool,
) -> dict:
    cfg = BotConfig.from_file()
    paths = RuntimePaths.from_config(cfg)
    sampler = _sampler_by_id(strategy_id)
    experiment_dir = runtime_dir / "experiments" / strategy_id
    experiment_dir.mkdir(parents=True, exist_ok=True)
    status = {
        "status": "ok",
        "strategy_id": strategy_id,
        "mode": "paper_only_research_sampler",
        "paper_only": True,
        "live_order_allowed": False,
        "mainnet_signed_action": False,
        "pid": os.getpid(),
        "iterations": 0,
    }
    for i in range(iterations):
        candles = _load_candle_cache(paths.runtime_dir / "candle_cache", coins, interval, hours_back)
        volumes = {coin: max(sum(c.volume for c in rows), cfg.min_volume_24h) for coin, rows in candles.items()}
        results = run_strategy_lab([sampler], candles, volumes=volumes) if candles else []
        result = results[0] if results else None
        row = {
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "strategy_id": strategy_id,
            "mode": "paper_only_research_sampler",
            "label": sampler.parameters.get("label"),
            "family": sampler.family,
            "paper_only": True,
            "research_sampler": True,
            "not_champion": True,
            "live_order_allowed": False,
            "mainnet_signed_action": False,
            "coins": [coin.upper() for coin in coins],
            "interval": interval,
            "hours_back": hours_back,
            "closed_trades_replay_window": result.closed_trades if result else 0,
            "total_pnl_replay_window": result.total_pnl_usd if result else 0,
            "profit_factor_replay_window": result.profit_factor if result else 0,
            "score_replay_window": result.score if result else -2.0,
            "top_trade_coins": sorted({trade.coin for trade in result.trades})[:8] if result else [],
            "final_decision": "research_observation_only",
            "would_enter_live": False,
        }
        _append_jsonl(experiment_dir / "signal_journal.jsonl", row)
        _append_jsonl(experiment_dir / "runtime_health.jsonl", {**row, "event": "heartbeat"})
        status.update({"iterations": i + 1, "last": row, "runtime_dir": str(experiment_dir)})
        if i < iterations - 1:
            time.sleep(interval_seconds)
    if json_output:
        print(json.dumps(status, indent=2, sort_keys=True, default=str))
    return status


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description="Run paper-only Strategy-Lab research sampler runtime.")
    parser.add_argument("--strategy-id", required=True)
    parser.add_argument("--coins", default="BTC,ETH,SOL,LINK,WLD,SUI,ENA,BCH")
    parser.add_argument("--interval", default="5m")
    parser.add_argument("--hours-back", type=int, default=1440)
    parser.add_argument("--iterations", type=int, default=1)
    parser.add_argument("--interval-seconds", type=float, default=60.0)
    parser.add_argument("--runtime-dir", default="runtime")
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args(argv)
    run_sampler(
        strategy_id=args.strategy_id,
        coins=[item.strip().upper() for item in args.coins.split(",") if item.strip()],
        interval=args.interval,
        hours_back=args.hours_back,
        iterations=args.iterations,
        interval_seconds=args.interval_seconds,
        runtime_dir=Path(args.runtime_dir),
        json_output=args.json,
    )
    return 0


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