from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal
from enum import Enum


class TradingMode(str, Enum):
    DRY_RUN = "dry_run"
    TESTNET_LIVE = "testnet_live"
    LIVE = "live"


class OrderSide(str, Enum):
    BUY = "BUY"
    SELL = "SELL"


class SignalType(str, Enum):
    BUY = "BUY"
    SELL = "SELL"
    HOLD = "HOLD"


@dataclass(frozen=True)
class Candle:
    symbol: str
    open_time: int
    close_time: int
    open: Decimal
    high: Decimal
    low: Decimal
    close: Decimal
    volume: Decimal
    quote_volume: Decimal = Decimal("0")
    trade_count: int = 0
    taker_buy_base_volume: Decimal = Decimal("0")
    taker_buy_quote_volume: Decimal = Decimal("0")

    def __post_init__(self) -> None:
        object.__setattr__(self, "symbol", self.symbol.upper())


@dataclass(frozen=True)
class Signal:
    symbol: str
    signal_type: SignalType
    side: OrderSide | None
    reason: str
    confidence: Decimal = Decimal("1")
    created_at_ms: int | None = None

    def __post_init__(self) -> None:
        object.__setattr__(self, "symbol", self.symbol.upper())


@dataclass(frozen=True)
class SymbolMetadata:
    symbol: str
    base_asset: str
    quote_asset: str
    min_notional: Decimal
    min_qty: Decimal
    step_size: Decimal
    tick_size: Decimal = Decimal("0")
    min_price: Decimal = Decimal("0")

    def __post_init__(self) -> None:
        object.__setattr__(self, "symbol", self.symbol.upper())
        object.__setattr__(self, "base_asset", self.base_asset.upper())
        object.__setattr__(self, "quote_asset", self.quote_asset.upper())


@dataclass(frozen=True)
class Balance:
    asset: str
    free: Decimal
    locked: Decimal = Decimal("0")

    def __post_init__(self) -> None:
        object.__setattr__(self, "asset", self.asset.upper())


@dataclass(frozen=True)
class AccountSnapshot:
    balances: dict[str, Balance]

    def __post_init__(self) -> None:
        object.__setattr__(
            self,
            "balances",
            {balance.asset: balance for balance in self.balances.values()},
        )

    def free(self, asset: str) -> Decimal:
        balance = self.balances.get(asset.upper())
        return balance.free if balance else Decimal("0")


@dataclass(frozen=True)
class RiskDecision:
    approved: bool
    reason: str
    signal: Signal
    quote_amount: Decimal | None = None


@dataclass(frozen=True)
class OrderIntent:
    symbol: str
    side: OrderSide
    quote_amount: Decimal
    client_order_id: str

    def __post_init__(self) -> None:
        object.__setattr__(self, "symbol", self.symbol.upper())


@dataclass(frozen=True)
class OrderResult:
    symbol: str
    side: OrderSide
    client_order_id: str
    status: str
    raw: dict
    dry_run: bool

    def __post_init__(self) -> None:
        object.__setattr__(self, "symbol", self.symbol.upper())
