"""
市场行情自动识别模块

基于 Binance 公开 API 判断当前市场状态（牛/熊/正常），用于自动切换 MARKET_SCHEME。
可被 crontab 定时任务调用（如每 4 小时执行一次）。

使用的接口（无需 API Key）：
- GET /fapi/v1/ticker/24hr：24h 涨跌幅
- GET /fapi/v1/premiumIndex：资金费率
- GET /futures/data/topLongShortPositionRatio：大户多空比
- GET /fapi/v1/klines：4H K 线（计算 trend_4h）
"""
import json
import logging
import ssl
import urllib.request
from typing import Optional, Tuple

logger = logging.getLogger(__name__)

BINANCE_FUTURES_BASE = "https://fapi.binance.com"
BINANCE_FUTURES_DATA = "https://fapi.binance.com/futures/data"
REQUEST_TIMEOUT = 15


def _http_get(url: str, params: Optional[dict] = None) -> Optional[dict]:
    """发起 GET 请求，返回 JSON 或 None。"""
    if params:
        qs = "&".join(f"{k}={v}" for k, v in params.items())
        url = f"{url}?{qs}"
    try:
        req = urllib.request.Request(url, headers={"Accept": "application/json"})
        ctx = ssl.create_default_context()
        with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT, context=ctx) as resp:
            raw = resp.read().decode("utf-8")
            data = json.loads(raw)
            return data
    except Exception as e:
        logger.warning(f"HTTP GET 失败 {url[:80]}: {e}")
        return None


def fetch_btc_24h_change() -> Optional[float]:
    """获取 BTCUSDT 24h 涨跌幅百分比。"""
    data = _http_get(f"{BINANCE_FUTURES_BASE}/fapi/v1/ticker/24hr", {"symbol": "BTCUSDT"})
    if not data or not isinstance(data, dict):
        return None
    try:
        return float(data.get("priceChangePercent", 0))
    except (TypeError, ValueError):
        return None


def fetch_btc_funding_rate() -> Optional[float]:
    """获取 BTCUSDT 最近资金费率。正=多头付费，负=空头付费。"""
    data = _http_get(f"{BINANCE_FUTURES_BASE}/fapi/v1/premiumIndex", {"symbol": "BTCUSDT"})
    if not data or not isinstance(data, dict):
        return None
    try:
        return float(data.get("lastFundingRate", 0))
    except (TypeError, ValueError):
        return None


def fetch_btc_long_short_ratio(period: str = "1d", limit: int = 1) -> Optional[float]:
    """获取 BTCUSDT 大户持仓多空比。>1 偏多，<1 偏空。"""
    data = _http_get(
        f"{BINANCE_FUTURES_DATA}/topLongShortPositionRatio",
        {"symbol": "BTCUSDT", "period": period, "limit": limit},
    )
    if not data or not isinstance(data, list) or len(data) == 0:
        return None
    try:
        return float(data[-1].get("longShortRatio", 1))
    except (TypeError, ValueError):
        return None


def fetch_btc_klines_4h(limit: int = 60) -> Optional[list]:
    """获取 BTCUSDT 4H K 线。"""
    data = _http_get(
        f"{BINANCE_FUTURES_BASE}/fapi/v1/klines",
        {"symbol": "BTCUSDT", "interval": "4h", "limit": limit},
    )
    if not data or not isinstance(data, list):
        return None
    return data


def _judge_trend_4h(
    price_4h: float,
    ema20_4h: Optional[float],
    ema50_4h: Optional[float],
    macd_hist: Optional[float],
) -> str:
    """根据 4H 价格、EMA、MACD 判断趋势方向。"""
    if ema20_4h is None:
        return "neutral"

    score = 0
    total = 0

    if price_4h > ema20_4h:
        score += 1
    elif price_4h < ema20_4h:
        score -= 1
    total += 1

    if ema50_4h is not None:
        if ema20_4h > ema50_4h:
            score += 1
        elif ema20_4h < ema50_4h:
            score -= 1
        total += 1

    if macd_hist is not None:
        if macd_hist > 0:
            score += 1
        elif macd_hist < 0:
            score -= 1
        total += 1

    if total == 0:
        return "neutral"
    if score >= 2:
        return "up"
    if score <= -2:
        return "down"
    return "neutral"


def compute_trend_4h_from_klines(klines: list) -> str:
    """从 4H K 线计算 trend_4h。"""
    try:
        from .indicators import TechnicalIndicators
    except ImportError:
        from indicators import TechnicalIndicators

    closes = [float(k[4]) for k in klines]  # 收盘价
    if len(closes) < 50:
        return "neutral"

    ema20 = TechnicalIndicators.calculate_ema(closes, 20)
    ema50 = TechnicalIndicators.calculate_ema(closes, 50)
    macd = TechnicalIndicators.calculate_macd(closes, 12, 26, 9)
    macd_hist = macd.get("histogram") if macd else None

    price_4h = closes[-1]
    return _judge_trend_4h(price_4h, ema20, ema50, macd_hist)


def detect_regime(
    change_24h: Optional[float] = None,
    funding_rate: Optional[float] = None,
    long_short_ratio: Optional[float] = None,
    trend_4h: Optional[str] = None,
    *,
    change_bull: float = 2.0,
    change_bear: float = -2.0,
    funding_bull: float = 0.00005,
    funding_bear: float = -0.00005,
    lsr_bull: float = 1.1,
    lsr_bear: float = 0.9,
) -> Tuple[str, dict]:
    """
    根据各项指标打分，综合判断市场行情。

    Returns:
        (regime, details): regime 为 'bull'|'bear'|'normal'，details 为各项得分详情。
    """
    score = 0
    details = {}

    # 1. 24h 涨跌幅
    if change_24h is not None:
        details["change_24h"] = round(change_24h, 2)
        if change_24h >= change_bull:
            score += 1
            details["change_score"] = 1
        elif change_24h <= change_bear:
            score -= 1
            details["change_score"] = -1
        else:
            details["change_score"] = 0

    # 2. 4H 趋势
    if trend_4h:
        details["trend_4h"] = trend_4h
        if trend_4h == "up":
            score += 1
            details["trend_score"] = 1
        elif trend_4h == "down":
            score -= 1
            details["trend_score"] = -1
        else:
            details["trend_score"] = 0

    # 3. 资金费率
    if funding_rate is not None:
        details["funding_rate"] = round(funding_rate, 6)
        if funding_rate >= funding_bull:
            score += 1
            details["funding_score"] = 1
        elif funding_rate <= funding_bear:
            score -= 1
            details["funding_score"] = -1
        else:
            details["funding_score"] = 0

    # 4. 大户多空比
    if long_short_ratio is not None:
        details["long_short_ratio"] = round(long_short_ratio, 4)
        if long_short_ratio >= lsr_bull:
            score += 1
            details["lsr_score"] = 1
        elif long_short_ratio <= lsr_bear:
            score -= 1
            details["lsr_score"] = -1
        else:
            details["lsr_score"] = 0

    details["total_score"] = score

    if score >= 2:
        return "bull", details
    if score <= -2:
        return "bear", details
    return "normal", details


def detect_market_regime(symbol: str = "BTCUSDT") -> Tuple[str, dict]:
    """
    主入口：拉取 Binance 数据并判断市场行情。

    Args:
        symbol: 基准交易对，默认 BTCUSDT

    Returns:
        (regime, details): regime 为 'bull'|'bear'|'normal'
    """
    if symbol != "BTCUSDT":
        logger.warning("当前仅支持 BTCUSDT，将使用 BTCUSDT")
        symbol = "BTCUSDT"

    change_24h = fetch_btc_24h_change()
    funding_rate = fetch_btc_funding_rate()
    long_short_ratio = fetch_btc_long_short_ratio(period="1d", limit=1)
    klines = fetch_btc_klines_4h(limit=60)
    trend_4h = compute_trend_4h_from_klines(klines) if klines else None

    regime, details = detect_regime(
        change_24h=change_24h,
        funding_rate=funding_rate,
        long_short_ratio=long_short_ratio,
        trend_4h=trend_4h,
    )
    return regime, details
