"""
数据模型定义 — 与 TS data/types/base.ts 对齐的 Pydantic 模型

Ticker / Trade / OrderBook / Kline 是系统中流通的核心行情数据结构，
字段语义与 Binance/OKX/Bybit 通用概念对齐，时间戳统一使用 Unix 毫秒。
"""

from typing import Literal

from pydantic import BaseModel, Field, field_validator


# ============================================================
# K 线周期类型
# ============================================================

KlineInterval = Literal["1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "1d", "1w", "1mon"]

# ============================================================
# 交易对类型
# ============================================================

PairType = Literal["spot", "um", "cm"]
"""交易对类型，与 TS data/types/kline.ts 的 PairType 对齐"""


# ============================================================
# 行情数据模型
# ============================================================


class Ticker(BaseModel):
    """24 小时滚动行情统计

    每笔成交触发推送，包含最近 24 小时的 OHLC、成交量、买卖盘口等统计信息。
    """

    exchange: str
    """交易所标识（如 binance）"""
    symbol: str
    """交易对符号（大写，如 BTCUSDT）"""

    # 24h 价格统计
    last_price: float = Field(alias="lastPrice")
    """最新成交价"""
    open_price: float = Field(alias="openPrice")
    """24h 开盘价"""
    high_price: float = Field(alias="highPrice")
    """24h 最高价"""
    low_price: float = Field(alias="lowPrice")
    """24h 最低价"""

    # 24h 成交量统计
    volume: float
    """24h 成交量（base 币种）"""
    quote_volume: float = Field(alias="quoteVolume")
    """24h 成交额（quote 币种）"""

    # 价格变化
    price_change: float = Field(alias="priceChange")
    """24h 价格变化"""
    price_change_percent: float = Field(alias="priceChangePercent")
    """24h 价格变化百分比（0.05 = 5%）"""

    # 最优买卖盘口
    bid_price: float = Field(alias="bidPrice")
    """买一价"""
    bid_qty: float = Field(alias="bidQty")
    """买一量"""
    ask_price: float = Field(alias="askPrice")
    """卖一价"""
    ask_qty: float = Field(alias="askQty")
    """卖一量"""

    # 时间戳
    event_time: float = Field(alias="eventTime")
    """事件发生时间（Unix 毫秒）"""
    close_time: float = Field(alias="closeTime")
    """交易所收盘时间（Unix 毫秒，用于判断 K 线是否闭合）"""


class Trade(BaseModel):
    """逐笔成交记录"""

    exchange: str
    """交易所标识"""
    symbol: str
    """交易对符号"""
    price: float
    """成交价"""
    amount: float
    """成交数量（base 币种）"""
    quote_amount: float = Field(alias="quoteAmount")
    """成交额（quote 币种 = price × amount）"""
    timestamp: float
    """成交时间（Unix 毫秒）"""
    is_buyer_maker: bool = Field(alias="isBuyerMaker")
    """买方是否为挂单方（true = 主动卖出 / taker sell）"""
    trade_id: str = Field(alias="tradeId")
    """交易所成交 ID"""


class OrderBook(BaseModel):
    """订单簿深度快照"""

    exchange: str
    """交易所标识"""
    symbol: str
    """交易对符号"""
    bids: list[tuple[float, float]]
    """买单列表 [[price, qty], ...]，按价格降序（买一在前）"""
    asks: list[tuple[float, float]]
    """卖单列表 [[price, qty], ...]，按价格升序（卖一在前）"""
    last_update_id: int = Field(alias="lastUpdateId")
    """上次更新 ID"""
    event_time: float = Field(alias="eventTime")
    """事件发生时间（Unix 毫秒）"""


class Kline(BaseModel):
    """标准化 K 线（OHLCV）

    K 线是最主要的行情输入，策略通过 on_kline() 接收此数据。
    open/high/low/close/volume 字段在 TS 侧为字符串以保持精度，
    模型在初始化时自动转换为 float。
    """

    exchange: str
    """交易所标识"""
    symbol: str
    """交易对符号"""
    interval: KlineInterval
    """K 线周期"""

    pair_type: PairType = Field(default="spot", alias="type")
    """交易对类型（spot / um / cm），与 TS Kline.type 对齐"""

    # 时间
    open_time: float = Field(alias="openTime")
    """开盘时间（Unix 毫秒）"""
    close_time: float = Field(alias="closeTime")
    """收盘时间（Unix 毫秒）"""

    # OHLCV
    open: float
    """开盘价"""
    high: float
    """最高价"""
    low: float
    """最低价"""
    close: float
    """收盘价"""
    volume: float
    """成交量（base 币种）"""

    # 扩展字段
    quote_volume: float = Field(default=0.0, alias="quoteVolume")
    """成交额（quote 币种）"""
    taker_buy_base_vol: float = Field(default=0.0, alias="takerBuyBaseVol")
    """主动买入成交量（base 币种）"""
    taker_buy_quote_vol: float = Field(default=0.0, alias="takerBuyQuoteVol")
    """主动买入成交额（quote 币种）"""
    trade_count: int = Field(default=0, alias="tradeCount")
    """成交笔数"""
    is_closed: bool = Field(alias="isClosed")
    """该 K 线是否已关闭（不再更新）"""

    # ── 字段校验：处理 TS 侧字符串 → float 转换 ──

    @field_validator(
        "open", "high", "low", "close", "volume",
        "quote_volume", "taker_buy_base_vol", "taker_buy_quote_vol",
        mode="before",
    )
    @classmethod
    def _coerce_float(cls, v: object) -> float:
        """将字符串类型数值转为 float，兼容 TS 侧 MessagePack 序列化格式"""
        if isinstance(v, str):
            return float(v)
        return float(v)

    @field_validator("trade_count", mode="before")
    @classmethod
    def _coerce_int(cls, v: object) -> int:
        """将字符串类型数值转为 int"""
        if isinstance(v, str):
            return int(v)
        return int(v)
