from __future__ import annotations

import argparse
import time
from datetime import datetime, timezone
from typing import Any

import requests

from config import BotConfig, RuntimePaths
from market_context import append_market_context_event, build_market_context_snapshot


INFO_URL = "https://api.hyperliquid.xyz/info"
DEFAULT_COINS = ("BTC", "ETH", "SOL", "HYPE")


def _post_info(payload: dict[str, Any], *, timeout: int = 15) -> Any:
    response = requests.post(INFO_URL, json=payload, timeout=timeout)
    response.raise_for_status()
    return response.json()


def fetch_meta_contexts() -> dict[str, dict[str, Any]]:
    data = _post_info({"type": "metaAndAssetCtxs"})
    if not isinstance(data, list) or len(data) < 2:
        return {}
    universe = data[0].get("universe", [])
    ctxs = data[1]
    out: dict[str, dict[str, Any]] = {}
    for asset, ctx in zip(universe, ctxs):
        name = str(asset.get("name", "")).upper()
        if name:
            out[name] = ctx
    return out


def fetch_candles(coin: str, *, interval: str = "15m", lookback_minutes: int = 24 * 60) -> list[dict[str, float]]:
    end_ms = int(time.time() * 1000)
    start_ms = end_ms - lookback_minutes * 60 * 1000
    raw = _post_info({
        "type": "candleSnapshot",
        "req": {
            "coin": coin.upper(),
            "interval": interval,
            "startTime": start_ms,
            "endTime": end_ms,
        },
    })
    candles = []
    for c in raw or []:
        candles.append({
            "open": float(c.get("o")),
            "high": float(c.get("h")),
            "low": float(c.get("l")),
            "close": float(c.get("c")),
            "volume": float(c.get("v", 0.0)),
        })
    return candles


def _float_or_none(value: Any) -> float | None:
    try:
        return None if value is None else float(value)
    except (TypeError, ValueError):
        return None


def collect_market_context(coins: list[str], *, interval: str = "15m") -> list[dict[str, Any]]:
    cfg = BotConfig.from_file()
    paths = RuntimePaths.from_config(cfg)
    paths.ensure_dirs()
    meta = fetch_meta_contexts()
    events = []
    for coin in coins:
        coin = coin.upper()
        candles = fetch_candles(coin, interval=interval)
        if len(candles) < 20:
            continue
        ctx = meta.get(coin, {})
        snapshot = build_market_context_snapshot(
            coin=coin,
            candles=candles,
            open_interest_usd=_float_or_none(ctx.get("openInterest")) or _float_or_none(ctx.get("openInterestUsd")),
            funding_rate=_float_or_none(ctx.get("funding")),
            source="hyperliquid",
            timeframe=interval,
            ts=datetime.now(timezone.utc),
        )
        events.append(append_market_context_event(paths.market_context, snapshot))
    return events


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description="Collect Hyperliquid market context snapshots for paper-trading analysis.")
    parser.add_argument("--coins", default=",".join(DEFAULT_COINS), help="Comma-separated coin list")
    parser.add_argument("--interval", default="15m")
    args = parser.parse_args(argv)
    coins = [x.strip().upper() for x in args.coins.split(",") if x.strip()]
    events = collect_market_context(coins, interval=args.interval)
    print(f"market_context_events={len(events)} coins={','.join(e['coin'] for e in events)}")
    return 0


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