"""Algo execution 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, Union

from pydantic import BaseModel, Field


class AlgoType(str, Enum):
    """Algorithm types."""
    TWAP = "twap"
    VWAP = "vwap"
    ICEBERG = "iceberg"
    CONDITIONAL = "conditional"


class AlgoOrderStatus(str, Enum):
    """Algo order status."""
    PENDING = "pending"
    RUNNING = "running"
    PAUSED = "paused"
    COMPLETED = "completed"
    CANCELLED = "cancelled"
    FAILED = "failed"
    EXPIRED = "expired"


class TriggerCondition(str, Enum):
    """Conditional order trigger conditions."""
    PRICE_ABOVE = "price_above"
    PRICE_BELOW = "price_below"
    PRICE_CROSS = "price_cross"


class VolumeProfileEntry(BaseModel):
    """Entry in a volume profile."""
    hour: int = Field(ge=0, le=23)
    volume_percent: float = Field(alias="volumePercent", ge=0, le=100)

    class Config:
        populate_by_name = True


class TwapParams(BaseModel):
    """TWAP algorithm parameters."""
    total_quantity: float = Field(alias="totalQuantity", gt=0)
    duration_seconds: int = Field(alias="durationSeconds", gt=0)
    slice_count: int = Field(alias="sliceCount", gt=0)
    jitter_percent: Optional[float] = Field(default=None, alias="jitterPercent", ge=0, le=50)
    min_slice_size: Optional[float] = Field(default=None, alias="minSliceSize", gt=0)
    price_limit: Optional[float] = Field(default=None, alias="priceLimit", gt=0)

    class Config:
        populate_by_name = True


class VwapParams(BaseModel):
    """VWAP algorithm parameters."""
    total_quantity: float = Field(alias="totalQuantity", gt=0)
    duration_seconds: int = Field(alias="durationSeconds", gt=0)
    participation_rate: Optional[float] = Field(default=None, alias="participationRate", gt=0, le=1)
    max_deviation_percent: Optional[float] = Field(default=None, alias="maxDeviationPercent", ge=0)
    volume_profile: Optional[List[VolumeProfileEntry]] = Field(default=None, alias="volumeProfile")
    price_limit: Optional[float] = Field(default=None, alias="priceLimit", gt=0)

    class Config:
        populate_by_name = True


class IcebergParams(BaseModel):
    """Iceberg algorithm parameters."""
    total_quantity: float = Field(alias="totalQuantity", gt=0)
    display_quantity: float = Field(alias="displayQuantity", gt=0)
    variance: Optional[float] = Field(default=None, ge=0, le=1)
    refresh_delay_seconds: Optional[int] = Field(default=None, alias="refreshDelaySeconds", ge=0)
    price_limit: Optional[float] = Field(default=None, alias="priceLimit", gt=0)
    price_limit_type: Optional[str] = Field(default=None, alias="priceLimitType")
    trailing_offset: Optional[float] = Field(default=None, alias="trailingOffset")

    class Config:
        populate_by_name = True


class ConditionalParams(BaseModel):
    """Conditional algorithm parameters."""
    trigger_condition: TriggerCondition = Field(alias="triggerCondition")
    trigger_price: float = Field(alias="triggerPrice", gt=0)
    quantity: float = Field(gt=0)
    order_type: Optional[str] = Field(default="market", alias="orderType")
    limit_price: Optional[float] = Field(default=None, alias="limitPrice", gt=0)
    expires_at: Optional[str] = Field(default=None, alias="expiresAt")
    reference_asset: Optional[str] = Field(default=None, alias="referenceAsset")

    class Config:
        populate_by_name = True


class AlgoExecutionState(BaseModel):
    """Execution state of an algo order."""
    started_at: Optional[datetime] = Field(default=None, alias="startedAt")
    completed_at: Optional[datetime] = Field(default=None, alias="completedAt")
    executed_quantity: str = Field(alias="executedQuantity")
    remaining_quantity: str = Field(alias="remainingQuantity")
    current_slice_index: int = Field(alias="currentSliceIndex")
    child_order_count: int = Field(alias="childOrderCount")

    class Config:
        populate_by_name = True


class AlgoMetrics(BaseModel):
    """Execution metrics for an algo order."""
    total_filled: str = Field(alias="totalFilled")
    avg_price: Optional[str] = Field(default=None, alias="avgPrice")
    slippage: Optional[str] = Field(default=None)
    execution_rate: str = Field(alias="executionRate")

    class Config:
        populate_by_name = True


class AlgoOrder(BaseModel):
    """Algo order model."""
    id: str
    asset: str
    side: str
    algo_type: AlgoType = Field(alias="algoType")
    status: AlgoOrderStatus
    params: Union[TwapParams, VwapParams, IcebergParams, ConditionalParams]
    execution_state: AlgoExecutionState = Field(alias="executionState")
    metrics: AlgoMetrics
    created_at: datetime = Field(alias="createdAt")
    updated_at: datetime = Field(alias="updatedAt")

    class Config:
        populate_by_name = True


class AlgoOrderEvent(BaseModel):
    """Algo order event."""
    id: str
    event_type: str = Field(alias="eventType")
    timestamp: datetime
    data: Dict[str, Any]

    class Config:
        populate_by_name = True


class CreateAlgoOrderRequest(BaseModel):
    """Request to create an algo order."""
    asset: str
    side: str
    algo_type: AlgoType = Field(alias="algoType")
    twap_params: Optional[TwapParams] = Field(default=None, alias="twapParams")
    vwap_params: Optional[VwapParams] = Field(default=None, alias="vwapParams")
    iceberg_params: Optional[IcebergParams] = Field(default=None, alias="icebergParams")
    conditional_params: Optional[ConditionalParams] = Field(default=None, alias="conditionalParams")
    metadata: Optional[Dict[str, Any]] = None

    class Config:
        populate_by_name = True
