"""Models for Execution Monitoring."""

from __future__ import annotations

from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


class ExecutionEventType(str, Enum):
    """Types of execution events."""

    ORDER_CREATED = "order_created"
    ORDER_SUBMITTED = "order_submitted"
    ORDER_ACKNOWLEDGED = "order_acknowledged"
    FILLED = "filled"
    PARTIAL_FILL = "partial_fill"
    CANCELLED = "cancelled"
    REJECTED = "rejected"
    EXPIRED = "expired"
    ALGO_STARTED = "algo_started"
    ALGO_PAUSED = "algo_paused"
    ALGO_RESUMED = "algo_resumed"
    ALGO_CANCELLED = "algo_cancelled"
    ALGO_COMPLETED = "algo_completed"
    SLICE_CREATED = "slice_created"
    SLICE_EXECUTED = "slice_executed"


class ExecutionPhase(str, Enum):
    """Phases of order execution."""

    ORDER_RECEIVED = "order_received"
    VALIDATION = "validation"
    RISK_CHECK = "risk_check"
    ORDER_SUBMITTED = "order_submitted"
    VENUE_ACKNOWLEDGED = "venue_acknowledged"
    FILL_RECEIVED = "fill_received"
    SETTLEMENT = "settlement"


class ErrorType(str, Enum):
    """Types of execution errors."""

    VALIDATION = "validation"
    RISK_LIMIT = "risk_limit"
    CONNECTIVITY = "connectivity"
    TIMEOUT = "timeout"
    VENUE = "venue"
    INSUFFICIENT_FUNDS = "insufficient_funds"
    PRICE_DEVIATION = "price_deviation"
    RATE_LIMIT = "rate_limit"
    AUTHENTICATION = "authentication"
    INTERNAL = "internal"
    UNKNOWN = "unknown"


class ErrorSeverity(str, Enum):
    """Error severity levels."""

    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class ExecutionEvent(BaseModel):
    """Execution event model."""

    event_id: str = Field(alias="eventId")
    event_type: ExecutionEventType = Field(alias="eventType")
    order_id: Optional[str] = Field(default=None, alias="orderId")
    algo_order_id: Optional[str] = Field(default=None, alias="algoOrderId")
    rfq_id: Optional[str] = Field(default=None, alias="rfqId")
    user_id: str = Field(alias="userId")
    timestamp: datetime
    phase: Optional[ExecutionPhase] = None
    data: Optional[Dict[str, Any]] = None

    class Config:
        populate_by_name = True


class ExecutionError(BaseModel):
    """Execution error model."""

    error_id: str = Field(alias="errorId")
    order_id: Optional[str] = Field(default=None, alias="orderId")
    algo_order_id: Optional[str] = Field(default=None, alias="algoOrderId")
    user_id: str = Field(alias="userId")
    error_type: ErrorType = Field(alias="errorType")
    severity: ErrorSeverity
    error_code: str = Field(alias="errorCode")
    message: str
    details: Optional[str] = None
    venue: Optional[str] = None
    asset: Optional[str] = None
    timestamp: datetime
    resolved: bool = False
    acknowledged: bool = False

    class Config:
        populate_by_name = True


class FillSummary(BaseModel):
    """Fill aggregation summary."""

    total_filled: float = Field(alias="totalFilled")
    total_notional: float = Field(alias="totalNotional")
    avg_price: float = Field(alias="avgPrice")
    vwap: float
    fill_count: int = Field(alias="fillCount")
    first_fill_time: Optional[datetime] = Field(default=None, alias="firstFillTime")
    last_fill_time: Optional[datetime] = Field(default=None, alias="lastFillTime")

    class Config:
        populate_by_name = True


class FillRateMetrics(BaseModel):
    """Fill rate metrics."""

    total_orders: int = Field(alias="totalOrders")
    filled_orders: int = Field(alias="filledOrders")
    partially_filled_orders: int = Field(alias="partiallyFilledOrders")
    rejected_orders: int = Field(alias="rejectedOrders")
    cancelled_orders: int = Field(alias="cancelledOrders")
    fill_rate: float = Field(alias="fillRate")
    average_fill_ratio: float = Field(alias="averageFillRatio")

    class Config:
        populate_by_name = True


class LatencyPercentiles(BaseModel):
    """Latency percentile distribution."""

    min: float
    max: float
    avg: float
    p50: float
    p75: float
    p90: float
    p95: float
    p99: float
    sample_count: int = Field(alias="sampleCount")

    class Config:
        populate_by_name = True


class SlippageMetrics(BaseModel):
    """Slippage metrics."""

    avg_slippage_bps: float = Field(alias="avgSlippageBps")
    worst_slippage_bps: float = Field(alias="worstSlippageBps")
    best_slippage_bps: float = Field(alias="bestSlippageBps")
    count: int

    class Config:
        populate_by_name = True


class ErrorSummary(BaseModel):
    """Error summary for a period."""

    by_type: Dict[str, int] = Field(alias="byType")
    by_venue: Dict[str, int] = Field(alias="byVenue")
    by_severity: Dict[str, int] = Field(alias="bySeverity")
    trend: Dict[str, Any]
    top_errors: List[Dict[str, Any]] = Field(alias="topErrors")
    unresolved: int

    class Config:
        populate_by_name = True


class ErrorPattern(BaseModel):
    """Detected error pattern."""

    pattern_id: str = Field(alias="patternId")
    description: str
    error_type: ErrorType = Field(alias="errorType")
    count: int
    frequency: float
    affected_orders: int = Field(alias="affectedOrders")
    affected_venues: List[str] = Field(alias="affectedVenues")
    first_seen: datetime = Field(alias="firstSeen")
    last_seen: datetime = Field(alias="lastSeen")
    is_anomaly: bool = Field(alias="isAnomaly")

    class Config:
        populate_by_name = True


class VolumeMetrics(BaseModel):
    """Volume metrics."""

    total_orders: int = Field(alias="totalOrders")
    total_quantity: float = Field(alias="totalQuantity")
    total_notional: float = Field(alias="totalNotional")
    buy_orders: int = Field(alias="buyOrders")
    sell_orders: int = Field(alias="sellOrders")
    buy_quantity: float = Field(alias="buyQuantity")
    sell_quantity: float = Field(alias="sellQuantity")

    class Config:
        populate_by_name = True


class FillMetrics(BaseModel):
    """Fill metrics."""

    total_orders: int = Field(alias="totalOrders")
    filled_orders: int = Field(alias="filledOrders")
    partial_fills: int = Field(alias="partialFills")
    rejections: int
    cancellations: int
    expirations: int
    fill_rate: float = Field(alias="fillRate")
    filled_quantity: float = Field(alias="filledQuantity")
    filled_notional: float = Field(alias="filledNotional")

    class Config:
        populate_by_name = True


class LatencyMetrics(BaseModel):
    """Latency metrics."""

    avg_latency_ms: float = Field(alias="avgLatencyMs")
    min_latency_ms: float = Field(alias="minLatencyMs")
    max_latency_ms: float = Field(alias="maxLatencyMs")
    p50_latency_ms: float = Field(alias="p50LatencyMs")
    p75_latency_ms: float = Field(alias="p75LatencyMs")
    p90_latency_ms: float = Field(alias="p90LatencyMs")
    p95_latency_ms: float = Field(alias="p95LatencyMs")
    p99_latency_ms: float = Field(alias="p99LatencyMs")
    sample_count: int = Field(alias="sampleCount")

    class Config:
        populate_by_name = True


class MetricsSnapshot(BaseModel):
    """Real-time metrics snapshot."""

    volume: VolumeMetrics
    fills: FillMetrics
    latency: LatencyMetrics
    errors: Dict[str, Any]

    class Config:
        populate_by_name = True


class Alert(BaseModel):
    """Monitoring alert."""

    type: str
    severity: str
    message: str
    timestamp: datetime


class DashboardData(BaseModel):
    """Dashboard data model."""

    realtime: MetricsSnapshot
    daily: Dict[str, Any]
    latency: Dict[str, Any]
    alerts: List[Alert]
    error_patterns: List[ErrorPattern] = Field(alias="errorPatterns")

    class Config:
        populate_by_name = True


class OrderMonitoring(BaseModel):
    """Order monitoring data."""

    order_id: str = Field(alias="orderId")
    timeline: List[ExecutionEvent]
    fills: FillSummary
    latency: Dict[str, Any]
    errors: List[ExecutionError]
    status: str

    class Config:
        populate_by_name = True


class AlgoMonitoring(BaseModel):
    """Algo order monitoring data."""

    algo_order_id: str = Field(alias="algoOrderId")
    timeline: List[ExecutionEvent]
    fills: FillSummary
    child_orders: List[str] = Field(alias="childOrders")
    progress: Dict[str, Any]
    latency: Optional[Dict[str, Any]]
    errors: List[ExecutionError]
    status: str

    class Config:
        populate_by_name = True
