"""OKX 合约 ID / 到期解析（交易所专属）。"""

from __future__ import annotations

import re
from datetime import datetime, timezone
from typing import Any

from ..expiry import expiry_ms_from_ymd

_DATE_RE = re.compile(r"^\d{6}$")

__all__ = [
    "expiry_ms_from_ymd",
    "parse_option_inst_id",
    "rows_to_option_contracts",
    "safe_float",
]


def safe_float(v: Any) -> float | None:
    if v is None or v == "":
        return None
    try:
        return float(v)
    except (TypeError, ValueError):
        return None


def parse_option_inst_id(inst_id: str) -> tuple[str | None, float | None, str | None]:
    """ETH-USD_UM-YYMMDD-STRIKE-C → (YYMMDD, strike, C|P)."""
    parts = (inst_id or "").strip().split("-")
    if len(parts) < 5:
        return None, None, None
    ymd = parts[-3]
    strike = safe_float(parts[-2])
    opt = parts[-1].upper()
    if not _DATE_RE.fullmatch(ymd) or strike is None or opt not in ("C", "P"):
        return None, None, None
    return ymd, strike, opt


def rows_to_option_contracts(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """
    归一化为策略层可用的中性结构：
    {inst_id, expiry_ymd, strike, side, ct_mult}
    """
    out: list[dict[str, Any]] = []
    for row in rows:
        if not isinstance(row, dict):
            continue
        state = str(row.get("state") or "live").lower()
        if state and state != "live":
            continue
        inst_id = str(row.get("instId") or "")
        y, stk, opt = parse_option_inst_id(inst_id)
        exp_ms = None
        if y is None or stk is None or opt is None:
            exp = safe_float(row.get("expTime"))
            if exp:
                ms = int(exp) if exp > 10_000_000_000 else int(exp * 1000)
                y = datetime.fromtimestamp(ms / 1000, tz=timezone.utc).strftime("%y%m%d")
                exp_ms = ms
            stk = safe_float(row.get("stk"))
            opt_raw = str(row.get("optType") or "").upper()
            opt = opt_raw if opt_raw in ("C", "P") else None
        if not inst_id or not y or stk is None or opt not in ("C", "P"):
            continue
        if exp_ms is None:
            exp_ms = expiry_ms_from_ymd(y)
        ct = safe_float(row.get("ctMult"))
        out.append(
            {
                "inst_id": inst_id,
                "expiry_ymd": y,
                "expiry_ms": int(exp_ms),
                "strike": float(stk),
                "side": opt,
                "ct_mult": float(ct) if ct and ct > 0 else None,
            }
        )
    return out
