"""
Domain models — mirrors market-data-service event contracts.

Tolerant parsing: unknown fields ignored, partial data accepted.
"""
from __future__ import annotations

import time
from datetime import datetime, timezone
from enum import Enum
from typing import Optional

from pydantic import BaseModel, Field


class EventType(str, Enum):
    TRADE = "trade"
    QUOTE = "quote"
    BOOK_L2 = "book_l2"
    HEARTBEAT = "heartbeat"


def _utc_now() -> datetime:
    return datetime.now(timezone.utc)


def _mono_ns() -> int:
    return time.monotonic_ns()


class BaseEvent(BaseModel, extra="ignore"):
    """Common fields — extra fields silently ignored."""

    event_type: EventType
    provider: str
    ts_recv: datetime = Field(default_factory=_utc_now)
    ts_recv_mono_ns: int = Field(default_factory=_mono_ns)


class TradeEvent(BaseEvent):
    event_type: EventType = EventType.TRADE
    symbol: str
    price: float
    size: float
    ts_exchange: Optional[datetime] = None
    side: Optional[str] = None
    trade_id: Optional[str] = None


class QuoteEvent(BaseEvent):
    event_type: EventType = EventType.QUOTE
    symbol: str
    bid: float
    ask: float
    bid_size: float
    ask_size: float
    ts_exchange: Optional[datetime] = None


class BookLevel(BaseModel, extra="ignore"):
    price: float
    size: float


class BookL2Event(BaseEvent):
    event_type: EventType = EventType.BOOK_L2
    symbol: str
    bids: list[BookLevel] = Field(default_factory=list)
    asks: list[BookLevel] = Field(default_factory=list)
    ts_exchange: Optional[datetime] = None


class HeartbeatEvent(BaseEvent):
    event_type: EventType = EventType.HEARTBEAT


# Union for parsing
Event = TradeEvent | QuoteEvent | BookL2Event | HeartbeatEvent


# ── Output models ──────────────────────────────────────────────────────


class FeatureSnapshot(BaseModel):
    """Published to senpai.features.{symbol}."""

    symbol: str
    ts: datetime = Field(default_factory=_utc_now)
    features: dict[str, float | None]


class TradeSignal(BaseModel):
    """Published to senpai.signals.{symbol}."""

    symbol: str
    ts: datetime = Field(default_factory=_utc_now)
    direction: str  # "long" | "short"
    confidence: float = 0.0  # 0..1
    reason: str = ""
    features: dict[str, float | None] = Field(default_factory=dict)


class AlertEvent(BaseModel):
    """Published to senpai.alerts."""

    ts: datetime = Field(default_factory=_utc_now)
    level: str = "warning"  # "warning" | "critical"
    alert_type: str  # "latency" | "gap" | "backpressure"
    message: str
    details: dict = Field(default_factory=dict)


# ── Parsing helper ─────────────────────────────────────────────────────

_EVENT_MAP: dict[str, type[BaseEvent]] = {
    "trade": TradeEvent,
    "quote": QuoteEvent,
    "book_l2": BookL2Event,
    "heartbeat": HeartbeatEvent,
}


def parse_event(data: dict) -> Event | None:
    """
    Parse a dict (from JSON) into the appropriate Event model.
    Returns None if event_type is unknown or data is invalid.
    """
    event_type = data.get("event_type")
    if not event_type:
        return None

    cls = _EVENT_MAP.get(event_type)
    if cls is None:
        return None

    try:
        return cls.model_validate(data)
    except Exception:
        return None
