"""Quote models for ZenOTC SDK (Market Making)."""

from __future__ import annotations

from datetime import datetime
from decimal import Decimal
from enum import Enum
from typing import Any, Dict, Optional

from pydantic import Field, field_validator

from zenotc.models.base import BaseModel, TimestampMixin


class QuoteStatus(str, Enum):
    """Quote status."""

    ACTIVE = "active"
    PARTIALLY_FILLED = "partially_filled"
    FILLED = "filled"
    CANCELLED = "cancelled"
    EXPIRED = "expired"


class QuoteRequest(BaseModel):
    """Request to submit a quote."""

    asset: str = Field(..., min_length=1, max_length=10, description="Asset symbol (e.g., BTC)")
    bid_price: Decimal = Field(..., gt=0, description="Bid price")
    ask_price: Decimal = Field(..., gt=0, description="Ask price")
    bid_size: Decimal = Field(..., gt=0, description="Bid size")
    ask_size: Decimal = Field(..., gt=0, description="Ask size")
    valid_for_seconds: int = Field(
        default=30, ge=1, le=300, description="Quote validity in seconds"
    )
    client_quote_id: Optional[str] = Field(
        None, max_length=64, description="Client-provided quote ID"
    )
    metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")

    @field_validator("ask_price")
    @classmethod
    def validate_spread(cls, v: Decimal, info: Any) -> Decimal:
        """Validate that ask price is greater than bid price."""
        bid_price = info.data.get("bid_price")
        if bid_price is not None and v <= bid_price:
            raise ValueError("ask_price must be greater than bid_price")
        return v


class QuoteUpdate(BaseModel):
    """Request to update a quote."""

    bid_price: Optional[Decimal] = Field(None, gt=0, description="New bid price")
    ask_price: Optional[Decimal] = Field(None, gt=0, description="New ask price")
    bid_size: Optional[Decimal] = Field(None, gt=0, description="New bid size")
    ask_size: Optional[Decimal] = Field(None, gt=0, description="New ask size")
    valid_for_seconds: Optional[int] = Field(
        None, ge=1, le=300, description="New validity in seconds"
    )


class Quote(TimestampMixin):
    """Quote representation."""

    id: str = Field(..., description="Quote ID")
    user_id: str = Field(..., description="Market maker user ID")
    asset: str = Field(..., description="Asset symbol")
    bid_price: Decimal = Field(..., description="Bid price")
    ask_price: Decimal = Field(..., description="Ask price")
    bid_size: Decimal = Field(..., description="Bid size")
    ask_size: Decimal = Field(..., description="Ask size")
    bid_filled: Decimal = Field(default=Decimal("0"), description="Filled bid quantity")
    ask_filled: Decimal = Field(default=Decimal("0"), description="Filled ask quantity")
    status: QuoteStatus = Field(..., description="Quote status")
    expires_at: datetime = Field(..., description="Quote expiration time")
    client_quote_id: Optional[str] = Field(None, description="Client-provided quote ID")
    metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")

    @property
    def spread(self) -> Decimal:
        """Get bid-ask spread."""
        return self.ask_price - self.bid_price

    @property
    def spread_percentage(self) -> float:
        """Get spread as percentage of mid price."""
        mid = (self.bid_price + self.ask_price) / 2
        if mid == 0:
            return 0.0
        return float(self.spread / mid * 100)

    @property
    def mid_price(self) -> Decimal:
        """Get mid price."""
        return (self.bid_price + self.ask_price) / 2

    @property
    def remaining_bid_size(self) -> Decimal:
        """Get remaining bid size."""
        return self.bid_size - self.bid_filled

    @property
    def remaining_ask_size(self) -> Decimal:
        """Get remaining ask size."""
        return self.ask_size - self.ask_filled

    @property
    def is_active(self) -> bool:
        """Check if quote is active."""
        return self.status in (QuoteStatus.ACTIVE, QuoteStatus.PARTIALLY_FILLED)

    @property
    def is_expired(self) -> bool:
        """Check if quote is expired based on expires_at."""
        return datetime.utcnow() > self.expires_at
