"""Crypto perp exchange contract. The domain/application depend only on these DTOs + Protocol, never on ccxt.
Perps need more than the equities `Broker` port: exchange filters, order book, leverage, signed positions,
reduce-only/post-only — so this is its own boundary."""
from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol


@dataclass(frozen=True, slots=True)
class SymbolFilter:
    symbol: str
    step_size: float     # LOT_SIZE: quantity increment
    tick_size: float     # PRICE_FILTER: price increment
    min_notional: float  # MIN_NOTIONAL (USD)


@dataclass(frozen=True, slots=True)
class OrderBook:
    symbol: str
    bid: float
    ask: float
    bid_qty: float
    ask_qty: float

    @property
    def mid(self) -> float:
        return (self.bid + self.ask) / 2.0


@dataclass(frozen=True, slots=True)
class PerpPosition:
    symbol: str
    qty: float           # signed base quantity (negative = short)
    entry_price: float
    leverage: int


@dataclass(frozen=True, slots=True)
class CryptoAccount:
    nlv: float                       # net liquidation value (USD)
    available_balance: float
    positions: dict[str, float]      # symbol -> signed base qty


@dataclass(frozen=True, slots=True)
class ChildOrder:
    symbol: str
    side: str            # "BUY" | "SELL"
    qty: float           # > 0, already rounded to step_size
    order_type: str      # "LIMIT" | "MARKET"
    price: float | None  # None for MARKET; rounded to tick_size for LIMIT
    reduce_only: bool
    post_only: bool      # maker-only (GTX) for LIMIT
    client_id: str       # deterministic, for idempotency
    time_in_force: str   # "GTX" (post-only) | "IOC" | "GTC"


@dataclass(frozen=True, slots=True)
class Fill:
    client_id: str
    symbol: str
    side: str
    qty: float           # filled base qty (0.0 if nothing filled)
    price: float         # avg fill price (0.0 if nothing filled)
    fee: float
    status: str          # "FILLED" | "PARTIAL" | "CANCELED" | "REJECTED" | "EXPIRED"


class CryptoExchange(Protocol):
    name: str

    def exchange_info(self) -> dict[str, SymbolFilter]: ...
    def order_book(self, symbol: str) -> OrderBook: ...
    def positions(self) -> list[PerpPosition]: ...
    def account(self) -> CryptoAccount: ...
    def set_leverage(self, symbol: str, leverage: int) -> None: ...
    def ensure_one_way_mode(self) -> None: ...
    def place(self, order: ChildOrder) -> Fill: ...
    def cancel(self, symbol: str, client_id: str) -> None: ...
    def order_status(self, symbol: str, client_id: str) -> Fill: ...
