"""
VIX term structure fetcher — VX futures curve, contango/backwardation regime.
Uses yfinance (^VIX, ^VXMT, ^VXV) + CBOE delayed quotes API as secondary.
No API key required.
"""
import logging
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

import requests
import yfinance as yf

logger = logging.getLogger(__name__)

CBOE_VX_URL = "https://cdn.cboe.com/api/global/delayed_quotes/futures/VX.json"

VIX_TICKERS = ["^VIX", "^VXV", "^VXMT"]


def _detect_regime(vix_spot: float, slope_1m_3m: float) -> str:
    if vix_spot > 30:
        return "crisis"
    elif slope_1m_3m < -2:
        return "backwardation_strong"
    elif slope_1m_3m < 0:
        return "backwardation_mild"
    elif slope_1m_3m > 5:
        return "contango_steep"
    return "contango_mild"


def _fetch_cboe_vx_futures() -> Optional[List[Dict]]:
    try:
        resp = requests.get(CBOE_VX_URL, timeout=15)
        resp.raise_for_status()
        payload = resp.json()
        data = payload.get("data", [])
        contracts = []
        for item in data[:5]:
            contracts.append({
                "symbol": item.get("symbol"),
                "expiration": item.get("expiration"),
                "last": item.get("last"),
                "bid": item.get("bid"),
                "ask": item.get("ask"),
            })
        return contracts if contracts else None
    except Exception as e:
        logger.warning(f"[VX] CBOE API unavailable: {e}")
        return None


def fetch_vx_report() -> Optional[Dict]:
    """Fetch VIX term structure and detect contango/backwardation regime. Returns None if yfinance fails."""
    report_date = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d")

    try:
        data = yf.download(VIX_TICKERS, period="5d", interval="1d", progress=False, auto_adjust=True)
        if data is None or data.empty:
            logger.warning("[VX] yfinance returned empty data")
            return None

        close = data["Close"] if "Close" in data.columns else data

        def latest_close(ticker: str) -> Optional[float]:
            try:
                col = close[ticker].dropna()
                if col.empty:
                    return None
                return float(col.iloc[-1])
            except Exception:
                return None

        vix_spot = latest_close("^VIX")
        vix_3m = latest_close("^VXV")
        vix_6m = latest_close("^VXMT")

        if vix_spot is None:
            logger.warning("[VX] ^VIX data unavailable")
            return None

    except Exception as e:
        logger.warning(f"[VX] yfinance download failed: {e}")
        return None

    slope_1m_3m = (vix_3m - vix_spot) if vix_3m is not None else None
    slope_3m_6m = (vix_6m - vix_3m) if (vix_6m is not None and vix_3m is not None) else None
    contango_pct = ((vix_3m - vix_spot) / vix_spot * 100) if vix_3m is not None else None

    regime = _detect_regime(vix_spot, slope_1m_3m if slope_1m_3m is not None else 0.0)

    cboe_contracts = _fetch_cboe_vx_futures()

    raw_data: Dict[str, Any] = {
        "vix_spot": round(vix_spot, 2),
        "vix_3m": round(vix_3m, 2) if vix_3m is not None else None,
        "vix_6m": round(vix_6m, 2) if vix_6m is not None else None,
        "slope_1m_3m": round(slope_1m_3m, 2) if slope_1m_3m is not None else None,
        "slope_3m_6m": round(slope_3m_6m, 2) if slope_3m_6m is not None else None,
        "contango_pct": round(contango_pct, 2) if contango_pct is not None else None,
        "regime": regime,
        "cboe_futures": cboe_contracts,
    }

    key_points: List[str] = []

    vix_3m_str = f"{vix_3m:.1f}" if vix_3m is not None else "N/A"
    vix_6m_str = f"{vix_6m:.1f}" if vix_6m is not None else "N/A"
    key_points.append(f"VIX spot: {vix_spot:.1f} | 3M: {vix_3m_str} | 6M: {vix_6m_str}")

    if slope_1m_3m is not None:
        key_points.append(
            f"Term structure slope (1M→3M): {slope_1m_3m:+.1f}pt → {regime}"
        )

    if regime in ("backwardation_strong", "backwardation_mild"):
        key_points.append("BACKWARDATION: front > back → elevated fear, options expensive")

    if contango_pct is not None and contango_pct > 10:
        monthly_decay = round(contango_pct / 12, 1)
        key_points.append(
            f"Steep contango: VXX roll decay ~{monthly_decay}%/month → premium selling environment"
        )

    if contango_pct is not None:
        key_points.append(f"Contango: {contango_pct:+.1f}%")

    if regime in ("crisis", "backwardation_strong"):
        signal_indices = "bearish"
    elif regime == "contango_steep":
        signal_indices = "bullish"
    else:
        signal_indices = "neutral"

    implications: List[str] = []

    if regime in ("backwardation_strong", "backwardation_mild"):
        implications.append("VXX/UVXY positive carry — consider long vol as hedge")
    elif regime == "contango_steep":
        implications.append(
            "High roll decay in VXX — premium selling favored, spreads over naked buys"
        )
    elif regime == "crisis":
        implications.append(
            "Extreme fear — tail protection is expensive, wait for calmer entry"
        )

    if vix_spot > 20:
        implications.append(
            f"Elevated VIX ({vix_spot:.1f}) — implied vol rich, consider selling premium with defined risk"
        )
    elif vix_spot < 14:
        implications.append(
            f"Low VIX ({vix_spot:.1f}) — vol cheap, consider buying tail protection"
        )

    if not implications:
        implications = ["VIX term structure neutral — no extreme regime detected"]

    abs_slope = abs(slope_1m_3m) if slope_1m_3m is not None else 0.0
    importance = 3 if (regime == "crisis" or abs_slope > 5) else 2

    slope_str = f"{slope_1m_3m:+.1f}pt" if slope_1m_3m is not None else "N/A"
    ai_summary = (
        f"VIX term structure ({report_date}). "
        f"Spot {vix_spot:.1f} | 3M {vix_3m_str} | 6M {vix_6m_str}. "
        f"Slope 1M→3M: {slope_str}. "
        f"Regime: {regime.upper()}. "
        f"Signal: {signal_indices.upper()}. "
        + implications[0]
    )

    return {
        "report_type": "vx_curve",
        "report_date": report_date,
        "title": f"VIX Term Structure — {report_date}",
        "source": "yfinance + CBOE delayed API",
        "importance": importance,
        "category": "volatility",
        "raw_data": raw_data,
        "key_points": key_points,
        "trading_implications": " | ".join(implications),
        "signal_energy": "neutral",
        "signal_metals": "neutral",
        "signal_indices": signal_indices,
        "signal_forex": "neutral",
        "ai_summary": ai_summary,
    }
