from __future__ import annotations

from fastapi import APIRouter, Query, HTTPException
from typing import List, Dict, Any

from app.services.crypto.binance_rest import fetch_klines as binance_klines
from app.services.metals.alpha_fx import fetch_fx_intraday, fetch_fx_daily
from app.utils.cache import TTLCache
from app.streaming.live_store import live_store

router = APIRouter(prefix="/ohlcv", tags=["OHLCV"])

_cache = TTLCache(default_ttl=60, maxsize=128)


def _resample(data: List[Dict[str, Any]], timeframe: str) -> List[Dict[str, Any]]:
    # data is ascending, 1m or 5m depending on source
    import math
    seconds_map = {"1m": 60, "5m": 300, "1h": 3600, "4h": 14400, "1d": 86400}
    tf_sec = seconds_map.get(timeframe, 60)
    buckets: Dict[int, Dict[str, Any]] = {}
    for d in data:
        b = (d["time"] // tf_sec) * tf_sec
        cur = buckets.get(b)
        if cur is None:
            buckets[b] = {
                "time": b,
                "open": d["open"],
                "high": d["high"],
                "low": d["low"],
                "close": d["close"],
                "volume": d.get("volume", 0.0),
            }
        else:
            cur["high"] = max(cur["high"], d["high"])
            cur["low"] = min(cur["low"], d["low"])
            cur["close"] = d["close"]
            cur["volume"] = cur.get("volume", 0.0) + d.get("volume", 0.0)
    out = list(buckets.values())
    out.sort(key=lambda x: x["time"]) 
    return out


def _ttl_for(sym: str, timeframe: str) -> int:
    # Tune TTL based on timeframe and provider characteristics
    if sym.startswith("XAU"):
        # Alpha Vantage free tier ~ 1/min practical cadence
        if timeframe in ("1m", "5m"): return 60
        if timeframe in ("1h", "4h"): return 300
        return 3600
    else:
        # Binance updates are frequent; cache briefly
        if timeframe == "1m": return 10
        if timeframe in ("5m",): return 20
        if timeframe in ("1h", "4h"): return 120
        return 900


@router.get("")
async def get_ohlcv(
    symbol: str = Query(..., description="e.g., BTCUSDT, ETHUSDT, XAUUSD"),
    timeframe: str = Query("1m", description="1m,5m,1h,4h,1d"),
    limit: int = Query(500, ge=10, le=1000),
) -> List[Dict[str, Any]]:
    try:
        sym = symbol.upper().replace("/", "")
        key = (sym, timeframe)
        cached = _cache.get(key)
        if cached is not None:
            return cached[-limit:]

        if sym.startswith("XAU"):
            # Prefer live store 1m if available (ingested by alpha_hub)
            live_1m = live_store.get_history(sym, "1m")
            if live_1m:
                if timeframe == "1m":
                    return live_1m[-limit:]
                data = _resample(live_1m, timeframe)
                return data[-limit:]
            # Fallback to Alpha Vantage REST
            if timeframe in ("1m", "5m"):
                base_tf = timeframe
                data = await fetch_fx_intraday(sym, interval="1min" if timeframe == "1m" else "5min")
            elif timeframe in ("1h", "4h"):
                base_tf = "5m"
                data = await fetch_fx_intraday(sym, interval="5min")
            else:  # daily
                base_tf = "1d"
                data = await fetch_fx_daily(sym)
            if timeframe != base_tf:
                data = _resample(data, timeframe)
            ttl = _ttl_for(sym, timeframe)
            _cache.set(key, data, ttl=ttl)
            return data[-limit:]
        else:
            # Binance
            if timeframe not in ("1m", "5m", "1h", "4h", "1d"):
                raise HTTPException(status_code=400, detail="Unsupported timeframe")
            # Prefer live store for 1m data if available
            live_1m = live_store.get_history(sym, "1m")
            if live_1m:
                if timeframe == "1m":
                    return live_1m[-limit:]
                # Resample from 1m to requested timeframe
                data = _resample(live_1m, timeframe)
                return data[-limit:]
            # Fallback to REST
            data = await binance_klines(sym, interval=timeframe, limit=1000)
            ttl = _ttl_for(sym, timeframe)
            _cache.set(key, data, ttl=ttl)
            return data[-limit:]
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
