"""成交价与手续费：滑点 = 1×f。"""

from __future__ import annotations

from dataclasses import asdict, dataclass


@dataclass(slots=True)
class PriceResult:
    base_px: float
    fill_px: float
    fee: float
    slip: float
    notional: float

    def to_dict(self) -> dict[str, float]:
        return asdict(self)


def option_intrinsic(*, option_side: str, strike: float, spot: float) -> float:
    """多头期权内在价值（USDT/ETH）。call=max(S−K,0)，put=max(K−S,0)。"""
    s = float(spot)
    k = float(strike)
    side = str(option_side).lower().strip()
    if side in ("call", "c"):
        return max(s - k, 0.0)
    if side in ("put", "p"):
        return max(k - s, 0.0)
    return 0.0


def is_deep_otm(
    *,
    option_side: str,
    strike: float,
    spot: float,
    max_intrinsic: float = 0.01,
) -> bool:
    """
    远虚：内在价值≈0（多头期权已无行权价值）。
    100×杠杆 ATM 在标的波动约1%后常落入此状态。
    """
    return option_intrinsic(
        option_side=option_side, strike=strike, spot=spot
    ) <= float(max_intrinsic)


def option_expiry_settle(
    *,
    intrinsic: float,
    qty_eth: float,
    fee_rate: float,
) -> PriceResult:
    """到期结算：按内在价值入账（对齐实盘），无买卖价差滑点，仅扣手续费。"""
    base = max(float(intrinsic), 0.0)
    fill = base
    f = float(fee_rate)
    notional = abs(fill * float(qty_eth))
    fee = notional * f
    return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=0.0, notional=notional)


def resolve_option_close_bid(
    *,
    bid: float | None,
    mark: float | None,
    intrinsic: float | None,
    bypass_liquidity: bool,
) -> float | None:
    """
    非到期平仓价（SIM）。
    - 常规：买一，且多头卖出不低于内在价值。
    - 紧急 bypass：对齐 OKX 市价卖，**只按买一**（不用标记/内在价值抬价；
      标记无法在交易所成交）。bypass 只绕过深度/偏差闸门。
    到期请用 option_expiry_settle，不要走本函数。
    """
    _ = mark  # 保留参数兼容调用方；紧急不再用标记定价
    if bypass_liquidity:
        if bid is None or bid < 0:
            return None
        return float(bid)
    if bid is None:
        return None
    if intrinsic is not None and intrinsic >= 0:
        return max(float(bid), float(intrinsic))
    return float(bid)


def perp_fill(
    *,
    side: str,
    action: str,
    bid: float,
    ask: float,
    qty_eth: float,
    fee_rate: float,
) -> PriceResult:
    """
    side: long|short（持仓方向意图：开仓要建立的方向 / 平仓时原持仓方向）
    action: open|close
    开多/平空: 吃卖一 ×(1+f)
    开空/平多: 吃买一 ×(1-f)
    """
    f = float(fee_rate)
    buying = (action == "open" and side == "long") or (action == "close" and side == "short")
    if buying:
        base = float(ask)
        fill = base * (1.0 + f)
    else:
        base = float(bid)
        fill = base * (1.0 - f)
    notional = abs(fill * qty_eth)
    fee = notional * f
    slip = abs(fill - base) * qty_eth
    return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=slip, notional=notional)


def option_fill(
    *,
    action: str,
    bid: float,
    ask: float,
    qty_eth: float,
    fee_rate: float,
) -> PriceResult:
    """开仓买入吃卖一；平仓卖出吃买一。"""
    f = float(fee_rate)
    if action == "open":
        base = float(ask)
        fill = base * (1.0 + f)
    else:
        base = float(bid)
        fill = base * (1.0 - f)
    notional = abs(fill * qty_eth)
    fee = notional * f
    slip = abs(fill - base) * qty_eth
    return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=slip, notional=notional)
