from __future__ import annotations

from fastapi import APIRouter, Query
from typing import Any, Dict, List, Optional
import math

from app.api.trading import simulation_state
from app.streaming.live_store import live_store

router = APIRouter(tags=["Performance"])  # paths mounted at /api


def _equity_from_live(symbol: str = "XAU/USD", timeframe: str = "1m", limit: int = 300) -> List[Dict[str, Any]]:
    bars = live_store.get_history(symbol, timeframe)
    if not bars:
        return []
    if limit > 0:
        bars = bars[-limit:]
    cash = float(simulation_state.get("cash", 0.0))
    qty = float(simulation_state.get("position", {}).get("quantity", 0.0) if simulation_state.get("position") else 0.0)
    out: List[Dict[str, Any]] = []
    for b in bars:
        out.append({
            "time": int(b["time"]),
            "equity": cash + qty * float(b["close"]),
        })
    return out


@router.get("/equity-history")
async def equity_history(symbol: str = Query("XAU/USD"), timeframe: str = Query("1m"), limit: int = Query(300, ge=1, le=5000)) -> List[Dict[str, Any]]:
    # Prefer recorded equity history if available
    hist = simulation_state.get("equity_history") or []
    if hist:
        if limit > 0:
            hist = hist[-limit:]
        return hist
    # Fallback: derive from current cash and open qty over historical closes
    return _equity_from_live(symbol, timeframe, limit)


def _max_drawdown(eqs: List[float]) -> float:
    max_peak = -math.inf
    max_dd = 0.0
    for v in eqs:
        if v > max_peak:
            max_peak = v
        dd = (max_peak - v) / max_peak if max_peak > 0 else 0.0
        if dd > max_dd:
            max_dd = dd
    return max_dd


@router.get("/performance")
async def performance(symbol: str = Query("XAU/USD"), timeframe: str = Query("1m"), limit: int = Query(300, ge=10, le=5000)) -> Dict[str, Any]:
    series = await equity_history(symbol=symbol, timeframe=timeframe, limit=limit)
    if not series or len(series) < 2:
        return {"available": False}

    eq = [float(x["equity"]) for x in series]
    rets = []
    for i in range(1, len(eq)):
        prev = eq[i-1]
        curr = eq[i]
        if prev > 0:
            rets.append(curr/prev - 1.0)
    if not rets:
        return {"available": False}

    avg = sum(rets) / len(rets)
    var = sum((r - avg)**2 for r in rets) / (len(rets) - 1) if len(rets) > 1 else 0.0
    std = math.sqrt(var)
    downside = [r for r in rets if r < 0]
    if downside:
        d_avg = sum(downside) / len(downside)
        d_var = sum((r - d_avg)**2 for r in downside) / (len(downside) - 1) if len(downside) > 1 else 0.0
        d_std = math.sqrt(d_var)
    else:
        d_std = 0.0

    periods_per_year = {
        "1m": 365*24*60,
        "5m": 365*24*12,
        "1h": 365*24,
        "4h": 365*6,
        "1d": 365,
    }.get(timeframe, 365)

    sharpe = (avg/std*math.sqrt(periods_per_year)) if std > 0 else None
    sortino = (avg/d_std*math.sqrt(periods_per_year)) if d_std > 0 else None
    total_return = (eq[-1]/eq[0] - 1.0) if eq[0] > 0 else None
    mdd = _max_drawdown(eq)

    return {
        "available": True,
        "count": len(eq),
        "total_return": total_return,
        "sharpe": sharpe,
        "sortino": sortino,
        "max_drawdown": mdd,
    }