"""OKX 单笔期权本位模式与币本位 USDT 预算."""
from __future__ import annotations

import os
from typing import Any


MODE_USDC = "usdc"
MODE_COIN = "coin"


def _env_bool(name: str, default: bool = False) -> bool:
    v = (os.getenv(name) or "").strip().lower()
    if not v:
        return default
    return v in ("1", "true", "yes", "on", "y")


def _env_float(name: str, default: float) -> float:
    try:
        return float(os.getenv(name) or default)
    except (TypeError, ValueError):
        return float(default)


def normalize_options_margin_mode(raw: Any = None) -> str:
    """返回 usdc | coin;未配置时默认币本位."""
    if raw is None:
        raw = os.getenv("OKX_OPTIONS_MARGIN_MODE")
    v = str(raw or MODE_COIN).strip().lower()
    if v in ("usdc", "usdc_margin", "usd_margin", "u本位", "u"):
        return MODE_USDC
    if v in ("coin", "coin_margin", "crypto", "crypto_margin", "币本位"):
        return MODE_COIN
    # 空串或未知值:默认币本位
    if not v:
        return MODE_COIN
    return MODE_COIN


def is_coin_margin_mode(raw: Any = None) -> bool:
    return normalize_options_margin_mode(raw) == MODE_COIN


def inst_family_for_underlying(underlying: str, *, margin_mode: str | None = None) -> str:
    u = (underlying or "ETH").strip().upper() or "ETH"
    mode = normalize_options_margin_mode(margin_mode)
    if mode == MODE_COIN:
        return f"{u}-USD"
    return f"{u}-USD_UM"


def margin_mode_from_inst_id(inst_id: str) -> str:
    inst = (inst_id or "").strip().upper()
    if not inst:
        return normalize_options_margin_mode()
    if "_UM" in inst:
        return MODE_USDC
    # ETH-USD-260701-2500-C / BTC-USD-...
    if "-USD-" in inst and "_UM" not in inst:
        return MODE_COIN
    return normalize_options_margin_mode()


def premium_ccy_for_mode(margin_mode: str, underlying: str = "ETH") -> str:
    if normalize_options_margin_mode(margin_mode) == MODE_COIN:
        return (underlying or "ETH").strip().upper() or "ETH"
    return "USDC"


def spot_quote_inst_id(underlying: str) -> str:
    """现货市价买卖: ETH-USDT / BTC-USDT."""
    u = (underlying or "ETH").strip().upper() or "ETH"
    return f"{u}-USDT"


def compute_coin_budget_usdt(
    trading_usdt: float,
    *,
    compound: bool | None = None,
    buffer: float | None = None,
    fixed_budget_usdt: float | None = None,
    max_enabled: bool | None = None,
    max_usdt: float | None = None,
) -> dict[str, Any]:
    """
    币本位单笔 USDT 预算.
    复利开: trading_usdt × buffer; 复利关: fixed × buffer.
    上限开: min(..., max_usdt).
    """
    bal = max(0.0, float(trading_usdt or 0))
    use_compound = _env_bool("OKX_OPTIONS_COIN_COMPOUND", True) if compound is None else bool(compound)
    buf = float(buffer) if buffer is not None else _env_float("OKX_OPTIONS_BUDGET_BUFFER", 0.95)
    if buf <= 0:
        buf = 0.95
    fixed = (
        float(fixed_budget_usdt)
        if fixed_budget_usdt is not None
        else _env_float("OKX_OPTIONS_COIN_BUDGET_USDT", 10.0)
    )
    if use_compound:
        raw = bal * buf
        source = "compound"
    else:
        raw = max(0.0, fixed) * buf
        source = "fixed"
    capped = False
    max_on = (
        _env_bool("OKX_OPTIONS_COIN_MAX_USDT_ENABLED", False)
        if max_enabled is None
        else bool(max_enabled)
    )
    max_n = (
        float(max_usdt)
        if max_usdt is not None
        else _env_float("OKX_OPTIONS_COIN_MAX_USDT", 50.0)
    )
    budget = raw
    if max_on and max_n > 0 and budget > max_n:
        budget = max_n
        capped = True
    return {
        "ok": budget > 0,
        "budget_usdt": round(budget, 8),
        "raw_usdt": round(raw, 8),
        "trading_usdt": round(bal, 8),
        "buffer": buf,
        "compound": use_compound,
        "source": source,
        "max_enabled": max_on,
        "max_usdt": max_n if max_on else None,
        "capped_by_max": capped,
        "msg": "" if budget > 0 else "交易账户 USDT 不足,无法计算币本位预算",
    }


def normalize_coin_spot_buy_buffer(raw: Any = None) -> float:
    """
    现货买入相对权利金的倍数缓冲.
    env OKX_OPTIONS_COIN_SPOT_BUY_BUFFER 默认 1.10(=多买 10%).
    也可写 0.10 表示 +10%.
    """
    if raw is None:
        v = _env_float("OKX_OPTIONS_COIN_SPOT_BUY_BUFFER", 1.10)
    else:
        try:
            v = float(raw)
        except (TypeError, ValueError):
            v = 1.10
    if v <= 0:
        return 1.10
    if v < 1.0:
        return 1.0 + v
    return v


def plan_coin_open_by_budget(
    *,
    quote_per_unit: float,
    ct_mult: float,
    min_sz: int,
    budget_usdt: float,
    index_px: float,
    ask_sz: float | None = None,
    spot_buy_buffer: float | None = None,
    target_sheets: int | None = None,
) -> dict[str, Any]:
    """
    先按预算/卖一估最大可开张数,再按「权利金 × 现货缓冲」算应买现货 USDT.
    不全额把预算换成币.
    """
    import math

    from lib.exchange.okx_options_lib import cap_option_buy_sheets_to_ask_depth

    ask = float(quote_per_unit or 0)
    mult = float(ct_mult or 0.01)
    need = max(1, int(min_sz or 1))
    budget = max(0.0, float(budget_usdt or 0))
    idx = float(index_px or 0)
    buf = normalize_coin_spot_buy_buffer(spot_buy_buffer)
    if ask <= 0 or mult <= 0:
        return {"ok": False, "msg": "卖一价无效", "sheets": 0, "buy_usdt": 0.0}
    if idx <= 0:
        return {"ok": False, "msg": "缺少指数价,无法估算买币 USDT", "sheets": 0, "buy_usdt": 0.0}
    if budget <= 0:
        return {"ok": False, "msg": "USDT 预算无效", "sheets": 0, "buy_usdt": 0.0}

    per_sheet_coin = ask * mult
    # 每张开仓需买的币(含缓冲)及其约合 USDT
    per_sheet_buy_coin = per_sheet_coin * buf
    per_sheet_usdt = per_sheet_buy_coin * idx
    if per_sheet_usdt <= 0:
        return {"ok": False, "msg": "无法计算单张买币成本", "sheets": 0, "buy_usdt": 0.0}

    max_by_budget = int(math.floor((budget / per_sheet_usdt) + 1e-12))
    if target_sheets is not None:
        try:
            want = int(target_sheets)
        except (TypeError, ValueError):
            want = 0
        if want < need:
            return {
                "ok": False,
                "msg": f"指定张数无效(需≥{need})",
                "sheets": 0,
                "buy_usdt": 0.0,
                "max_by_budget": max_by_budget,
            }
        sheets = min(want, max_by_budget)
        if sheets < want:
            return {
                "ok": False,
                "msg": (
                    f"预算约可开 {max_by_budget} 张(含现货缓冲×{buf:g}),"
                    f"不足指定 {want} 张"
                ),
                "sheets": 0,
                "buy_usdt": 0.0,
                "max_by_budget": max_by_budget,
                "spot_buy_buffer": buf,
            }
    else:
        sheets = max_by_budget

    capped, cap_msg = cap_option_buy_sheets_to_ask_depth(sheets, ask_sz, min_sz=need)
    ask_depth_capped = False
    if capped is None:
        return {
            "ok": False,
            "msg": cap_msg or "卖一深度不足",
            "sheets": 0,
            "buy_usdt": 0.0,
            "spot_buy_buffer": buf,
        }
    if int(capped) < sheets:
        sheets = int(capped)
        ask_depth_capped = True

    if sheets < need:
        return {
            "ok": False,
            "msg": (
                f"预算不足,无法买入 {need} 张"
                f"(单张约需 {per_sheet_usdt:.4f} USDT,含现货缓冲×{buf:g})"
            ),
            "sheets": sheets,
            "buy_usdt": 0.0,
            "per_sheet_usdt": round(per_sheet_usdt, 8),
            "spot_buy_buffer": buf,
            "max_by_budget": max_by_budget,
        }

    premium_coin = sheets * per_sheet_coin
    buy_coin = premium_coin * buf
    buy_usdt = min(budget, buy_coin * idx)
    # 再保险:向下对齐,避免浮点导致略超预算
    buy_usdt = min(budget, round(buy_usdt, 8))
    out = {
        "ok": True,
        "msg": "" if not ask_depth_capped else (cap_msg or f"已按卖一深度限制为 {sheets} 张"),
        "sheets": sheets,
        "eth_amount": round(sheets * mult, 8),
        "coin_premium": round(premium_coin, 8),
        "total_premium": round(premium_coin, 8),
        "per_sheet_coin": per_sheet_coin,
        "buy_coin": round(buy_coin, 8),
        "buy_usdt": round(buy_usdt, 8),
        "budget_usdt": round(budget, 8),
        "spot_buy_buffer": buf,
        "index_px": idx,
        "max_by_budget": max_by_budget,
        "ask_depth_capped": ask_depth_capped,
        "est_note": (
            f"按最大可开 {sheets} 张×卖一权利金×现货缓冲{buf:g}估买币;"
            f"不全额兑换预算"
        ),
    }
    if target_sheets is not None:
        out["est_note"] = (
            f"指定 {sheets} 张×卖一权利金×现货缓冲{buf:g}估买币;不全额兑换"
        )
        out["target_sheets"] = int(target_sheets)
    return out


def calc_sheets_from_coin_balance(
    *,
    quote_per_unit: float,
    ct_mult: float,
    min_sz: int,
    coin_available: float,
) -> dict[str, Any]:
    """用可用标的币尽量开满(权利金以币计)."""
    import math

    ask = float(quote_per_unit or 0)
    mult = float(ct_mult or 0.01)
    need = max(1, int(min_sz or 1))
    coin = max(0.0, float(coin_available or 0))
    # 留一点手续费/精度缓冲,避免算满张后下单 51008
    coin_eff = coin * 0.97
    if ask <= 0 or mult <= 0:
        return {"ok": False, "msg": "卖一价无效", "sheets": 0, "coin_premium": 0.0}
    per_sheet = ask * mult
    if per_sheet <= 0:
        return {"ok": False, "msg": "无法计算单张权利金(币)", "sheets": 0, "coin_premium": 0.0}
    sheets = int(math.floor((coin_eff / per_sheet) + 1e-12))
    if sheets < need:
        return {
            "ok": False,
            "msg": f"可用币不足,无法买入 {need} 张(单张约 {per_sheet:.8g} 币,可用 {coin:g})",
            "sheets": sheets,
            "coin_premium": round(sheets * per_sheet, 8),
            "per_sheet_coin": per_sheet,
        }
    prem = sheets * per_sheet
    return {
        "ok": True,
        "msg": "",
        "sheets": sheets,
        "coin_premium": round(prem, 8),
        "per_sheet_coin": per_sheet,
        "eth_amount": round(sheets * mult, 8),
    }
