"""
OKX 挂单聚合:普通委托 + 算法单(conditional / oco / trigger).
交易所 App「止盈止损」页多为 orders-algo-pending,仅 fetch_open_orders 默认拿不到.
"""
from __future__ import annotations

from typing import Any


def _order_dedupe_key(order: dict) -> str:
    info = order.get("info") or {}
    if not isinstance(info, dict):
        info = {}
    return str(order.get("id") or info.get("algoId") or info.get("ordId") or "")


def _okx_algo_cancel_id(order_id: str) -> str:
    oid = str(order_id or "")
    if ":" in oid:
        return oid.split(":", 1)[0]
    return oid


def _okx_order_needs_stop_cancel_param(order: dict) -> bool:
    """OKX 条件/算法单撤单须 params.stop=True,否则 cancel_order 走普通单接口会静默失败."""
    if not isinstance(order, dict):
        return False
    info = order.get("info") or {}
    if not isinstance(info, dict):
        info = {}
    if order.get("stopLossPrice") is not None or order.get("takeProfitPrice") is not None:
        return True
    if info.get("algoId") or info.get("slTriggerPx") or info.get("tpTriggerPx"):
        return True
    typ = str(order.get("type") or info.get("ordType") or "").lower()
    for token in ("conditional", "oco", "trigger", "move_order_stop", "iceberg"):
        if token in typ:
            return True
    return False


def fetch_okx_all_open_orders(ex, exchange_symbol: str) -> list[dict]:
    """合并 OKX 普通挂单与算法挂单(去重)."""
    if not exchange_symbol:
        return []
    ex.load_markets()
    sym = exchange_symbol
    try:
        sym = ex.market(exchange_symbol)["symbol"]
    except Exception:
        pass
    seen: set[str] = set()
    out: list[dict] = []

    def add_batch(batch: list | None) -> None:
        for o in batch or []:
            if not isinstance(o, dict):
                continue
            k = _order_dedupe_key(o)
            if not k or k in seen:
                continue
            seen.add(k)
            out.append(o)

    try:
        add_batch(ex.fetch_open_orders(sym))
    except Exception:
        pass
    for params in (
        {"ordType": "conditional"},
        {"ordType": "oco"},
        {"trigger": True},
    ):
        try:
            add_batch(ex.fetch_open_orders(sym, params=dict(params)))
        except Exception:
            pass
    return out


def cancel_okx_all_open_orders(ex, exchange_symbol: str) -> int:
    """
    撤销某合约全部挂单(普通 + 条件/算法).
    OKX 止盈止损在 orders-algo-pending,必须用 stop=True 才能撤掉.
    """
    if not exchange_symbol:
        return 0
    ex.load_markets()
    sym = exchange_symbol
    try:
        sym = ex.market(exchange_symbol)["symbol"]
    except Exception:
        pass
    n = 0
    for o in fetch_okx_all_open_orders(ex, sym):
        oid = _order_dedupe_key(o)
        if not oid:
            continue
        cancel_id = _okx_algo_cancel_id(oid)
        params = {"stop": True} if _okx_order_needs_stop_cancel_param(o) else None
        try:
            ex.cancel_order(cancel_id, sym, params)
            n += 1
            continue
        except Exception:
            pass
        try:
            ex.cancel_order(oid, sym, params)
            n += 1
        except Exception:
            pass
    try:
        ex.cancel_all_orders(sym)
    except Exception:
        pass
    return n
