"""
=========================================
CV6 AI Trading OS
Market API
=========================================
"""

import random
import time as _time
from typing import List, Optional

from fastapi import APIRouter, Query
from loguru import logger

from app.schemas.market_schema import (
    MarketRequest,
    MarketResponse
)

from app.services.market_service import MarketService


router = APIRouter(
    prefix="/market",
    tags=["Market"]
)

service = MarketService()

# ── Angel One singleton — module-level so the session persists across requests ──
_angel_broker = None

def _get_angel():
    """Return a connected AngelOneBroker instance (cached at module level)."""
    global _angel_broker
    try:
        from app.broker.angel_one import AngelOneBroker
        if _angel_broker is None:
            _angel_broker = AngelOneBroker()
        if not _angel_broker.connected:
            result = _angel_broker.connect()
            if not result.get("success"):
                logger.warning(f"[LivePrice] Angel One connect failed: {result.get('message')}")
                return None
        return _angel_broker
    except Exception as e:
        logger.warning(f"[LivePrice] Angel One init error: {e}")
        return None

# Angel One symbol token map — required for ltpData call
# Format: { NSE_SYMBOL: (exchange, tradingsymbol, symboltoken) }
_ANGEL_TOKENS = {
    "NIFTY 50":  ("NSE", "Nifty 50",   "99926000"),
    "BANKNIFTY": ("NSE", "Nifty Bank",  "99926009"),
    "RELIANCE":  ("NSE", "RELIANCE",    "2885"),
    "TCS":       ("NSE", "TCS",         "11536"),
    "INFY":      ("NSE", "INFY",        "1594"),
    "HDFCBANK":  ("NSE", "HDFCBANK",    "1333"),
    "ICICIBANK": ("NSE", "ICICIBANK",   "4963"),
    "SBIN":      ("NSE", "SBIN",        "3045"),
    "WIPRO":     ("NSE", "WIPRO",       "3787"),
    "AXISBANK":  ("NSE", "AXISBANK",    "5900"),
    "HCLTECH":   ("NSE", "HCLTECH",     "7229"),
    "KOTAKBANK": ("NSE", "KOTAKBANK",   "1922"),
    "LT":        ("NSE", "LT",          "11483"),
    "ITC":       ("NSE", "ITC",         "1660"),
    "BAJFINANCE":("NSE", "BAJFINANCE",  "317"),
    "MARUTI":    ("NSE", "MARUTI",      "10999"),
    "SUNPHARMA": ("NSE", "SUNPHARMA",   "3351"),
    "TITAN":     ("NSE", "TITAN",       "3506"),
    "ADANIPORTS":("NSE", "ADANIPORTS",  "15083"),
    "NTPC":      ("NSE", "NTPC",        "11630"),
    "TATAMOTORS":("NSE", "TATAMOTORS",  "3456"),
    "TATASTEEL": ("NSE", "TATASTEEL",   "3499"),
    "HINDUNILVR":("NSE", "HINDUNILVR",  "1394"),
    "BHARTIARTL":("NSE", "BHARTIARTL",  "10604"),
    "ONGC":      ("NSE", "ONGC",        "2475"),
    "POWERGRID": ("NSE", "POWERGRID",   "14977"),
    "TECHM":     ("NSE", "TECHM",       "13538"),
    "JSWSTEEL":  ("NSE", "JSWSTEEL",    "11723"),
    "COALINDIA": ("NSE", "COALINDIA",   "20374"),
    "DRREDDY":   ("NSE", "DRREDDY",     "881"),
    "CIPLA":     ("NSE", "CIPLA",       "694"),
    "M&M":       ("NSE", "M&M",         "2031"),
    "HEROMOTOCO":("NSE", "HEROMOTOCO",  "1348"),
    "EICHERMOT": ("NSE", "EICHERMOT",   "910"),
    "HINDALCO":  ("NSE", "HINDALCO",    "1363"),
    "ULTRACEMCO":("NSE", "ULTRACEMCO",  "11532"),
    "GRASIM":    ("NSE", "GRASIM",      "1232"),
    "INDUSINDBK":("NSE", "INDUSINDBK",  "5258"),
    "BPCL":      ("NSE", "BPCL",        "526"),
    "DIVISLAB":  ("NSE", "DIVISLAB",    "10940"),
    "NESTLEIND": ("NSE", "NESTLEIND",   "17963"),
    "BRITANNIA": ("NSE", "BRITANNIA",   "547"),
    "APOLLOHOSP":("NSE", "APOLLOHOSP",  "157"),
    "TATACONSUM":("NSE", "TATACONSUM",  "3432"),
    "SBILIFE":   ("NSE", "SBILIFE",     "21808"),
    "HDFCLIFE":  ("NSE", "HDFCLIFE",    "467"),
    "BAJAJFINSV":("NSE", "BAJAJFINSV",  "16675"),
    "SHRIRAMFIN":("NSE", "SHRIRAMFIN",  "4306"),
    "ADANIENT":  ("NSE", "ADANIENT",    "25"),
}


@router.post(
    "/data",
    response_model=MarketResponse
)
def get_market_data(data: MarketRequest):
    """
    Get Market Data
    """

    result = service.get_market_data(
        data.symbol
    )

    return MarketResponse(**result)


# ── OHLCV seed prices (same as backtest engine for consistency) ──────────────
_SEED_PRICES = {
    # Indices
    "NIFTY": 23500, "NIFTY 50": 23500, "NIFTY50": 24732,
    "BANKNIFTY": 49800, "NIFTY BANK": 49800,
    # Large Cap
    "RELIANCE": 2950,  "TCS": 3718,     "INFY": 1956,
    "HDFCBANK": 1687,  "ICICIBANK": 1232, "SBIN": 812,
    "WIPRO": 543,      "AXISBANK": 1145,  "HCLTECH": 1642,
    "KOTAKBANK": 1832, "LT": 3582,       "ITC": 463,
    "BAJFINANCE": 6840,"MARUTI": 10850,  "SUNPHARMA": 1720,
    "TITAN": 3340,     "ADANIPORTS": 1180,"NTPC": 342,
    "TATAMOTORS": 965, "TATASTEEL": 145, "HINDUNILVR": 2620,
    "BHARTIARTL": 1680,"ONGC": 263,      "POWERGRID": 320,
    "TECHM": 1562,     "JSWSTEEL": 890,  "COALINDIA": 415,
    "DRREDDY": 5740,   "CIPLA": 1480,    "M&M": 2880,
    "HEROMOTOCO": 4920,"EICHERMOT": 4780,"HINDALCO": 672,
    "ULTRACEMCO": 10900,"GRASIM": 2680,  "INDUSINDBK": 950,
    "BPCL": 310,       "DIVISLAB": 4850, "NESTLEIND": 2160,
    "BRITANNIA": 4960, "APOLLOHOSP": 6850,"TATACONSUM": 880,
    "SBILIFE": 1680,   "HDFCLIFE": 690,  "BAJAJFINSV": 1640,
    "SHRIRAMFIN": 620, "ADANIENT": 2680,
}

_TF_SECS = {
    "1m": 60, "3m": 180, "5m": 300, "15m": 900, "30m": 1800,
    "1h": 3600, "4h": 14400, "1D": 86400, "1W": 604800,
}


@router.get("/history")
def get_market_history(
    symbol: str = Query("NIFTY50", description="Symbol"),
    tf:     str = Query("5m",      description="Timeframe: 1m 5m 15m 1h 1D"),
    count:  int = Query(120,       le=500, description="Number of candles"),
):
    """
    Return deterministic OHLCV candles for charting.
    Uses a seeded random walk so the same symbol + tf always returns
    the same historical shape, stable across page refreshes.
    """
    sym = symbol.upper()
    base = _SEED_PRICES.get(sym, 1000)
    interval = _TF_SECS.get(tf, 300)
    now = int(_time.time())

    rng = random.Random(hash(sym + tf))   # deterministic per symbol+tf
    candles = []
    cur = base * 0.88
    for i in range(count, 0, -1):
        o = round(cur, 2)
        chg = (rng.random() - 0.478) * base * 0.005
        c = round(max(o + chg, base * 0.5), 2)
        h = round(max(o, c) * (1 + rng.random() * 0.002), 2)
        lo = round(min(o, c) * (1 - rng.random() * 0.002), 2)
        vol = int(rng.uniform(5000, 50000))
        candles.append({
            "time":   now - i * interval,
            "open":   o,
            "high":   h,
            "low":    lo,
            "close":  c,
            "volume": vol,
        })
        cur = c

    return {"symbol": sym, "tf": tf, "candles": candles}


@router.get("/live")
def get_live_price(
    symbol: str = Query("NIFTY 50", description="NSE symbol"),
):
    """
    Fetch real-time LTP for an NSE symbol.

    Priority:
      1. Angel One WebSocket tick cache (live_feed) — real-time push
      2. Angel One REST ltpData — per-request pull
      3. Simulated seed price — fallback when broker offline

    source = 'websocket' | 'live' | 'simulated'
    """
    sym = symbol.upper().strip()

    # ── 1. WebSocket live feed (real-time) ────────────────────────────────────
    try:
        from app.market.live_feed import live_feed as _lf
        if _lf.is_connected():
            price_data = _lf.get_price_data(sym)
            if price_data and price_data.get("ltp", 0) > 0:
                return price_data
    except Exception as _lf_err:
        logger.debug(f"[LivePrice] WebSocket feed error for {sym}: {_lf_err}")

    # ── 2. Angel One REST (hardcoded token list) ──────────────────────────────
    if sym in _ANGEL_TOKENS:
        broker = _get_angel()
        if broker:
            try:
                exch, trading_sym, token = _ANGEL_TOKENS[sym]
                resp = broker.quotes({
                    "exchange": exch,
                    "tradingsymbol": trading_sym,
                    "symboltoken": token,
                })
                if resp and resp.get("status") and resp.get("data"):
                    d = resp["data"]
                    ltp  = float(d.get("ltp",  0))
                    open_ = float(d.get("open", ltp))
                    high = float(d.get("high", ltp))
                    low  = float(d.get("low",  ltp))
                    chg_pct = round(((ltp - open_) / open_ * 100) if open_ else 0, 2)
                    return {
                        "symbol": sym,
                        "ltp":    ltp,
                        "open":   open_,
                        "high":   high,
                        "low":    low,
                        "change": round(ltp - open_, 2),
                        "change_pct": chg_pct,
                        "volume": int(d.get("tradedVolume", 0)),
                        "source": "live",
                    }
            except Exception as e:
                logger.warning(f"[LivePrice] quotes() failed for {sym}: {e}")
                # Reset cached broker so next call re-authenticates
                global _angel_broker
                _angel_broker = None

    # Fallback — simulated seed price
    base = _SEED_PRICES.get(sym, 1000)
    rng = random.Random(int(_time.time() // 60) + hash(sym))  # changes per minute
    chg_frac = (rng.random() - 0.49) * 0.008
    ltp  = round(base * (1 + chg_frac), 2)
    open_ = round(base * (1 - abs(chg_frac) * 0.3), 2)
    high = round(max(open_, ltp) * (1 + rng.random() * 0.003), 2)
    low  = round(min(open_, ltp) * (1 - rng.random() * 0.003), 2)
    chg_pct = round((ltp - open_) / open_ * 100, 2) if open_ else 0
    return {
        "symbol": sym,
        "ltp":    ltp,
        "open":   open_,
        "high":   high,
        "low":    low,
        "change": round(ltp - open_, 2),
        "change_pct": chg_pct,
        "volume": int(rng.uniform(50000, 5_000_000)),
        "source": "simulated",
    }


@router.get("/live/bulk")
def get_live_prices_bulk(
    symbols: str = Query("NIFTY 50,BANKNIFTY,RELIANCE", description="Comma-separated symbols"),
):
    """Fetch live/simulated prices for multiple symbols at once."""
    sym_list = [s.strip().upper() for s in symbols.split(",") if s.strip()][:20]
    results = {}
    for sym in sym_list:
        results[sym] = get_live_price(symbol=sym)
    return {"success": True, "prices": results}