"""Order models for ZenOTC SDK."""

from __future__ import annotations

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

from pydantic import Field

from zenotc.models.base import BaseModel, TimestampMixin


class OrderSide(str, Enum):
    """Order side."""

    BUY = "buy"
    SELL = "sell"


class OrderType(str, Enum):
    """Order type."""

    LIMIT = "limit"
    MARKET = "market"


class OrderStatus(str, Enum):
    """Order status."""

    PENDING = "pending"
    OPEN = "open"
    PARTIALLY_FILLED = "partially_filled"
    FILLED = "filled"
    CANCELLED = "cancelled"
    REJECTED = "rejected"
    EXPIRED = "expired"


class OrderRequest(BaseModel):
    """Request to create an order."""

    side: OrderSide = Field(..., description="Order side (buy/sell)")
    asset: str = Field(..., min_length=1, max_length=10, description="Asset symbol (e.g., BTC)")
    quantity: Decimal = Field(..., gt=0, description="Order quantity")
    price: Optional[Decimal] = Field(None, gt=0, description="Limit price (required for limit orders)")
    order_type: OrderType = Field(default=OrderType.LIMIT, description="Order type")
    time_in_force: str = Field(default="GTC", description="Time in force (GTC, IOC, FOK)")
    client_order_id: Optional[str] = Field(
        None, max_length=64, description="Client-provided order ID"
    )
    metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")


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

    id: str = Field(..., description="Order ID")
    user_id: Optional[str] = Field(None, description="User ID")
    side: OrderSide = Field(..., description="Order side")
    asset: str = Field(..., description="Asset symbol")
    quantity: Decimal = Field(..., description="Order quantity")
    filled_quantity: Decimal = Field(default=Decimal("0"), description="Filled quantity")
    price: Optional[Decimal] = Field(None, description="Limit price")
    average_price: Optional[Decimal] = Field(None, description="Average fill price")
    order_type: OrderType = Field(..., description="Order type")
    status: OrderStatus = Field(..., description="Order status")
    time_in_force: str = Field(..., description="Time in force")
    client_order_id: Optional[str] = Field(None, description="Client-provided order ID")
    reject_reason: Optional[str] = Field(None, description="Rejection reason if rejected")
    expires_at: Optional[datetime] = Field(None, description="Expiration time")
    metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")

    @property
    def remaining_quantity(self) -> Decimal:
        """Get remaining unfilled quantity."""
        return self.quantity - self.filled_quantity

    @property
    def is_active(self) -> bool:
        """Check if order is active."""
        return self.status in (OrderStatus.PENDING, OrderStatus.OPEN, OrderStatus.PARTIALLY_FILLED)

    @property
    def is_complete(self) -> bool:
        """Check if order is complete."""
        return self.status in (
            OrderStatus.FILLED,
            OrderStatus.CANCELLED,
            OrderStatus.REJECTED,
            OrderStatus.EXPIRED,
        )

    @property
    def fill_percentage(self) -> float:
        """Get fill percentage."""
        if self.quantity == 0:
            return 0.0
        return float(self.filled_quantity / self.quantity * 100)


class BatchOrderRequest(BaseModel):
    """Request to create multiple orders."""

    orders: List[OrderRequest] = Field(..., min_length=1, max_length=100, description="List of orders")


class BatchOrderResponse(BaseModel):
    """Response for batch order creation."""

    successful: List[Order] = Field(..., description="Successfully created orders")
    failed: List[Dict[str, Any]] = Field(..., description="Failed orders with error details")
    total_submitted: int = Field(..., description="Total orders submitted")
    total_successful: int = Field(..., description="Total successful orders")
    total_failed: int = Field(..., description="Total failed orders")
