"""趋势回调:各交易所止损刷新,市价加/平仓(通过 app 模块能力探测)."""
from __future__ import annotations

import time
from typing import Any


def _m(cfg: dict) -> Any:
    return cfg["app_module"]


def trend_refresh_stop_only(cfg: dict, exchange_symbol: str, direction: str, stop_loss: float) -> None:
    m = _m(cfg)
    if hasattr(m, "_gate_place_stop_loss_only_position"):
        if hasattr(m, "cancel_gate_swap_trigger_orders"):
            m.cancel_gate_swap_trigger_orders(exchange_symbol)
        m._gate_place_stop_loss_only_position(exchange_symbol, direction, stop_loss)
        return
    if hasattr(m, "_binance_place_stop_loss_only"):
        m._binance_place_stop_loss_only(exchange_symbol, direction, stop_loss)
        return
    if hasattr(m, "_okx_place_stop_loss_only"):
        m._okx_place_stop_loss_only(exchange_symbol, direction, stop_loss)
        return
    raise RuntimeError("当前实例未配置趋势回调止损挂单能力")


def trend_market_add(cfg: dict, exchange_symbol: str, direction: str, contracts: float, leverage: int):
    m = _m(cfg)
    ex = m.exchange
    m.ensure_markets_loaded()
    ex.set_leverage(int(leverage), exchange_symbol)
    side = "buy" if direction == "long" else "sell"
    if hasattr(m, "build_gate_order_params"):
        params = m.build_gate_order_params(direction, reduce_only=False)
    elif hasattr(m, "build_binance_order_params"):
        params = m.build_binance_order_params(direction, reduce_only=False)
    elif hasattr(m, "build_okx_order_params"):
        params = m.build_okx_order_params(direction, reduce_only=False)
    else:
        params = {}
    order_params = params if params is not None else {}
    return ex.create_order(exchange_symbol, "market", side, float(contracts), None, order_params)


def trend_market_close(cfg: dict, exchange_symbol: str, direction: str, pos_qty: float, leverage: int):
    m = _m(cfg)
    ex = m.exchange
    m.ensure_markets_loaded()
    ex.set_leverage(int(leverage), exchange_symbol)
    side = "sell" if direction == "long" else "buy"
    amt = float(ex.amount_to_precision(exchange_symbol, float(pos_qty)))
    if hasattr(m, "close_exchange_order"):
        row = {
            "exchange_symbol": exchange_symbol,
            "symbol": exchange_symbol,
            "direction": direction,
            "order_amount": amt,
        }
        return m.close_exchange_order(row)
    if hasattr(m, "build_gate_order_params"):
        params = m.build_gate_order_params(direction, reduce_only=True)
        return ex.create_order(exchange_symbol, "market", side, amt, None, params)
    if hasattr(m, "build_binance_order_params"):
        for params in m._binance_market_close_param_candidates(direction):
            try:
                return ex.create_order(exchange_symbol, "market", side, amt, None, params)
            except Exception as e:
                if not m._is_binance_close_param_retryable(str(e)):
                    raise
        raise RuntimeError("平仓失败")
    if hasattr(m, "build_okx_order_params"):
        params = m.build_okx_order_params(direction, reduce_only=True)
        return ex.create_order(exchange_symbol, "market", side, amt, None, params)
    return ex.create_order(exchange_symbol, "market", side, amt, None, {"reduceOnly": True})


def trend_replace_tpsl(cfg: dict, order_row: dict, stop_loss: float, take_profit: float) -> None:
    """趋势保本移交:先撤条件单再挂保本止损 + 计划止盈(与下单监控一致)."""
    m = _m(cfg)
    fn = getattr(m, "replace_active_monitor_tpsl_on_exchange", None)
    if not callable(fn):
        raise RuntimeError("当前实例未配置止盈止损同步能力")
    fn(order_row, float(stop_loss), float(take_profit))


def cancel_symbol_orders(cfg: dict, exchange_symbol: str) -> None:
    m = _m(cfg)
    if hasattr(m, "cancel_all_open_orders_for_symbol"):
        m.cancel_all_open_orders_for_symbol(exchange_symbol)
        return
    if hasattr(m, "cancel_gate_swap_trigger_orders"):
        m.cancel_gate_swap_trigger_orders(exchange_symbol)
    if hasattr(m, "cancel_binance_futures_open_orders"):
        m.cancel_binance_futures_open_orders(exchange_symbol)
    if hasattr(m, "cancel_okx_swap_open_orders"):
        m.cancel_okx_swap_open_orders(exchange_symbol)
