from __future__ import annotations

from dataclasses import dataclass


@dataclass(slots=True)
class Signal:
    bias: str  # strike_below_spot | strike_above_spot | call_ask_gt_put | put_ask_gt_call
    option_side: str  # call | put
    perp_side: str  # long | short
    call_ask: float
    put_ask: float


def decide(
    call_ask: float | None,
    put_ask: float | None,
    *,
    strike: float | None = None,
    mark_px: float | None = None,
) -> Signal | None:
    """
    开仓方向：
    - 行权价 < 标的 → 买 Call + 永续空（ATM 偏下）
    - 行权价 > 标的 → 买 Put + 永续多（ATM 偏上）
    - 行权价 ≈ 标的 → 回退 Call/Put 卖一比价
    """
    if call_ask is None or put_ask is None:
        return None
    ca = float(call_ask)
    pa = float(put_ask)

    if strike is not None and mark_px is not None and float(mark_px) > 0:
        diff = float(strike) - float(mark_px)
        if diff < -1e-9:
            return Signal(
                bias="strike_below_spot",
                option_side="call",
                perp_side="short",
                call_ask=ca,
                put_ask=pa,
            )
        if diff > 1e-9:
            return Signal(
                bias="strike_above_spot",
                option_side="put",
                perp_side="long",
                call_ask=ca,
                put_ask=pa,
            )

    if ca > pa:
        return Signal(
            bias="call_ask_gt_put",
            option_side="call",
            perp_side="short",
            call_ask=ca,
            put_ask=pa,
        )
    if pa > ca:
        return Signal(
            bias="put_ask_gt_call",
            option_side="put",
            perp_side="long",
            call_ask=ca,
            put_ask=pa,
        )
    return None


def decide_fixed(
    call_ask: float | None,
    put_ask: float | None,
    *,
    perp_side: str,
) -> Signal | None:
    """
    固定方向：
    - 永续多 → 买 Put
    - 永续空 → 买 Call
    """
    if call_ask is None or put_ask is None:
        return None
    side = (perp_side or "").strip().lower()
    ca = float(call_ask)
    pa = float(put_ask)
    if side == "long":
        return Signal(
            bias="fixed_long_put",
            option_side="put",
            perp_side="long",
            call_ask=ca,
            put_ask=pa,
        )
    if side == "short":
        return Signal(
            bias="fixed_short_call",
            option_side="call",
            perp_side="short",
            call_ask=ca,
            put_ask=pa,
        )
    return None
