"""Ingress models for vikdata API.

ALL field names use snake_case to match the backend API.

NOTE: Types like status, destination_type are stored as strings.
Valid values come from database lookup tables, not hardcoded enums.
"""

from datetime import datetime
from typing import Any, Literal
from uuid import UUID

from pydantic import BaseModel, Field


# =============================================================================
# Ingress Core
# =============================================================================


class IngressResources(BaseModel):
    """Ingress resource configuration."""

    cpu: str = Field(..., description="CPU allocation (e.g., '100m', '1')")
    memory: str = Field(..., description="Memory allocation (e.g., '128Mi', '1Gi')")


class IngressCore(BaseModel):
    """Ingress core response model."""

    id: UUID = Field(..., description="Core ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    series_id: UUID | None = Field(default=None, description="Plan series ID")
    subscription_id: UUID | None = Field(default=None, description="Subscription ID")
    name: str = Field(..., min_length=1, max_length=255, description="Core name")
    slug: str = Field(..., description="URL-friendly slug")
    status: str = Field(..., description="Core status (from lookup)")
    replicas: int = Field(..., gt=0, description="Number of replicas")
    resources: IngressResources = Field(..., description="Resource allocation")
    error_message: str | None = Field(default=None, description="Error message if status is error")
    k8s_namespace: str | None = Field(default=None, description="Kubernetes namespace")
    k8s_deployment_name: str | None = Field(default=None, description="Kubernetes deployment name")
    ingress_url: str | None = Field(default=None, description="Ingress endpoint URL")
    preview_enabled: bool = Field(..., description="Whether preview is enabled")
    preview_rate_limit: int = Field(..., gt=0, description="Preview rate limit per second")
    preview_buffer_size: int = Field(..., gt=0, description="Preview buffer size")
    preview_sample_percent: int = Field(..., ge=1, le=100, description="Preview sample percentage")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class IngressCoreListItem(BaseModel):
    """Ingress core list item (subset of fields)."""

    id: UUID = Field(..., description="Core ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    series_id: UUID | None = Field(default=None, description="Plan series ID")
    subscription_id: UUID | None = Field(default=None, description="Subscription ID")
    name: str = Field(..., description="Core name")
    slug: str = Field(..., description="URL-friendly slug")
    status: str = Field(..., description="Core status (from lookup)")
    replicas: int = Field(..., description="Number of replicas")
    ingress_url: str | None = Field(default=None, description="Ingress endpoint URL")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class CreateIngressCoreRequest(BaseModel):
    """Create ingress core request."""

    subscription_id: UUID = Field(..., description="Subscription ID for billing")
    name: str = Field(..., min_length=1, max_length=255, description="Core name")
    slug: str | None = Field(default=None, min_length=1, max_length=63, description="URL-friendly slug")
    replicas: int | None = Field(default=None, gt=0, description="Number of replicas")
    resources: IngressResources | None = Field(default=None, description="Resource allocation")


class UpdateIngressCoreRequest(BaseModel):
    """Update ingress core request."""

    name: str | None = Field(default=None, min_length=1, max_length=255, description="Core name")
    replicas: int | None = Field(default=None, gt=0, description="Number of replicas")
    resources: IngressResources | None = Field(default=None, description="Resource allocation")


# =============================================================================
# Ingress Channel
# =============================================================================


class IngressChannel(BaseModel):
    """Ingress channel response model."""

    id: UUID = Field(..., description="Channel ID")
    core_id: UUID = Field(..., description="Parent core ID")
    name: str = Field(..., min_length=1, max_length=255, description="Channel name")
    json_schema: dict[str, Any] = Field(
        default_factory=dict, alias="schema", description="JSON schema for validation"
    )
    transforms: list[dict[str, Any]] = Field(default_factory=list, description="Transform pipeline")
    routing_rules: list[dict[str, Any]] = Field(default_factory=list, description="Routing rules")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")

    model_config = {"populate_by_name": True}


class IngressChannelListItem(BaseModel):
    """Ingress channel list item (subset of fields)."""

    id: UUID = Field(..., description="Channel ID")
    core_id: UUID = Field(..., description="Parent core ID")
    name: str = Field(..., description="Channel name")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class CreateIngressChannelRequest(BaseModel):
    """Create ingress channel request."""

    core_id: UUID = Field(..., description="Parent core ID")
    name: str = Field(..., min_length=1, max_length=255, description="Channel name")
    json_schema: dict[str, Any] | None = Field(
        default=None, alias="schema", description="JSON schema for validation"
    )
    transforms: list[dict[str, Any]] | None = Field(default=None, description="Transform pipeline")
    routing_rules: list[dict[str, Any]] | None = Field(default=None, description="Routing rules")
    destination_ids: list[UUID] | None = Field(default=None, description="Destination IDs to link")

    model_config = {"populate_by_name": True}


class UpdateIngressChannelRequest(BaseModel):
    """Update ingress channel request."""

    name: str | None = Field(default=None, min_length=1, max_length=255, description="Channel name")
    json_schema: dict[str, Any] | None = Field(
        default=None, alias="schema", description="JSON schema for validation"
    )
    transforms: list[dict[str, Any]] | None = Field(default=None, description="Transform pipeline")
    routing_rules: list[dict[str, Any]] | None = Field(default=None, description="Routing rules")
    destination_ids: list[UUID] | None = Field(default=None, description="Destination IDs to link")

    model_config = {"populate_by_name": True}


# =============================================================================
# Ingress Destination
# =============================================================================


class IngressDestination(BaseModel):
    """Ingress destination response model."""

    id: UUID = Field(..., description="Destination ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    name: str = Field(..., min_length=1, max_length=255, description="Destination name")
    type: str = Field(..., description="Destination type (from lookup)")
    config: dict[str, Any] = Field(default_factory=dict, description="Destination configuration")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class IngressDestinationListItem(BaseModel):
    """Ingress destination list item (subset of fields)."""

    id: UUID = Field(..., description="Destination ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    name: str = Field(..., description="Destination name")
    type: str = Field(..., description="Destination type (from lookup)")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class CreateIngressDestinationRequest(BaseModel):
    """Create ingress destination request."""

    name: str = Field(..., min_length=1, max_length=255, description="Destination name")
    type: str = Field(..., description="Destination type (from lookup)")
    config: dict[str, Any] | None = Field(default=None, description="Destination configuration")


class UpdateIngressDestinationRequest(BaseModel):
    """Update ingress destination request."""

    name: str | None = Field(default=None, min_length=1, max_length=255, description="Destination name")
    type: str | None = Field(default=None, description="Destination type (from lookup)")
    config: dict[str, Any] | None = Field(default=None, description="Destination configuration")


# =============================================================================
# Preview Configuration
# =============================================================================


class PreviewConfigUpdate(BaseModel):
    """Preview configuration update request."""

    rate_limit: int | None = Field(default=None, ge=1, le=100, description="Rate limit per second")
    buffer_size: int | None = Field(default=None, ge=10, le=1000, description="Buffer size")
    sample_percent: int | None = Field(default=None, ge=1, le=100, description="Sample percentage")


class PreviewEventMetadata(BaseModel):
    """Preview event metadata."""

    request_id: str = Field(..., description="Request ID")
    source_ip: str = Field(..., description="Source IP address")
    ingress_timestamp: str = Field(..., description="Ingress timestamp")
    transformations_applied: list[str] = Field(..., description="Applied transformations")
    destination_count: int = Field(..., description="Number of destinations")


class IngressPreviewEvent(BaseModel):
    """Ingress preview event (received via WebSocket)."""

    event_type: Literal["ingress.preview"] = Field(default="ingress.preview", description="Event type")
    core_id: UUID = Field(..., description="Core ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    channel_id: UUID = Field(..., description="Channel ID")
    channel_name: str = Field(..., description="Channel name")
    data: dict[str, Any] = Field(..., description="Event data")
    metadata: PreviewEventMetadata = Field(..., description="Event metadata")
    published_at: str = Field(..., description="Publish timestamp")


# =============================================================================
# Ingress Metrics
# =============================================================================


class IngressMetric(BaseModel):
    """Ingress metric data point."""

    time: datetime = Field(..., description="Metric timestamp")
    core_id: UUID = Field(..., description="Core ID")
    channel_id: UUID | None = Field(default=None, description="Channel ID (if channel-specific)")
    requests_total: int = Field(..., ge=0, description="Total requests")
    requests_failed: int = Field(..., ge=0, description="Failed requests")
    latency_p50: float | None = Field(default=None, description="P50 latency in ms")
    latency_p95: float | None = Field(default=None, description="P95 latency in ms")
    latency_p99: float | None = Field(default=None, description="P99 latency in ms")


# =============================================================================
# Query Parameters
# =============================================================================


class CoreListParams(BaseModel):
    """Query parameters for listing cores."""

    page: int | None = Field(default=1, ge=1, description="Page number")
    per_page: int | None = Field(default=20, ge=1, le=100, description="Items per page")
    status: str | None = Field(default=None, description="Filter by status (from lookup)")
    series_id: UUID | None = Field(default=None, description="Filter by series")
    search: str | None = Field(default=None, description="Search by name or slug")


class ChannelListParams(BaseModel):
    """Query parameters for listing channels."""

    page: int | None = Field(default=1, ge=1, description="Page number")
    per_page: int | None = Field(default=20, ge=1, le=100, description="Items per page")
    core_id: UUID | None = Field(default=None, description="Filter by core")
    search: str | None = Field(default=None, description="Search by name")


class DestinationListParams(BaseModel):
    """Query parameters for listing destinations."""

    page: int | None = Field(default=1, ge=1, description="Page number")
    per_page: int | None = Field(default=20, ge=1, le=100, description="Items per page")
    type: str | None = Field(default=None, description="Filter by type (from lookup)")
    search: str | None = Field(default=None, description="Search by name")


class MetricsQueryParams(BaseModel):
    """Query parameters for metrics."""

    core_id: UUID = Field(..., description="Core ID")
    channel_id: UUID | None = Field(default=None, description="Channel ID (optional)")
    start: datetime = Field(..., description="Start timestamp")
    end: datetime = Field(..., description="End timestamp")
    interval: str | None = Field(default="1h", description="Aggregation interval")
