"""Upload-related data models."""

from datetime import datetime
from enum import Enum
from typing import Any, Union

from pydantic import BaseModel, ConfigDict, Field, model_validator


class UploadStatus(str, Enum):
    """Status of an upload session."""

    PENDING = "pending"
    UPLOADING = "uploading"
    COMPLETED = "completed"
    FAILED = "failed"
    ABORTED = "aborted"


class PartMetadata(BaseModel):
    """Metadata for a single upload part."""

    model_config = ConfigDict(populate_by_name=True)

    part_number: int = Field(alias="partNumber")
    etag: str


class UploadSession(BaseModel):
    """Details of an upload session."""

    model_config = ConfigDict(populate_by_name=True)

    session_id: str = Field(alias="sessionId")
    object_key: str = Field(alias="objectKey")
    file_name: str = Field(alias="fileName")
    file_size: int = Field(alias="fileSize")
    uploaded_size: int = Field(default=0, alias="uploadedSize")
    content_type: str = Field(alias="contentType")
    status: UploadStatus
    upload_id: Union[str, None] = Field(default=None, alias="uploadId")
    shortcut: Union[str, None] = None
    total_parts: Union[int, None] = Field(default=None, alias="totalParts")
    completed_parts: list[int] = Field(default_factory=list, alias="completedParts")
    is_public: bool = Field(default=False, alias="isPublic")
    metadata: Union[dict[str, Any], None] = None
    created_at: datetime = Field(alias="createdAt")
    completed_at: Union[datetime, None] = Field(default=None, alias="completedAt")

    @model_validator(mode="before")
    @classmethod
    def normalize_data(cls, data: Any) -> Any:
        """Normalize API response data before validation."""
        if isinstance(data, dict):
            # Handle 'id' -> 'sessionId' mapping
            if "id" in data and "sessionId" not in data:
                data["sessionId"] = data.pop("id")
            # Handle None for completedParts - convert to empty list
            if data.get("completedParts") is None:
                data["completedParts"] = []
        return data


class InitiateUploadRequest(BaseModel):
    """Request payload for initiating an upload."""

    model_config = ConfigDict(populate_by_name=True)

    file_name: str = Field(alias="fileName")
    file_size: int = Field(alias="fileSize")
    content_type: str = Field(alias="contentType")
    metadata: Union[dict[str, Any], None] = None
    use_multipart: bool = Field(default=False, alias="useMultipart")
    is_public: bool = Field(default=False, alias="isPublic")


class InitiateUploadResponse(BaseModel):
    """Response from initiating an upload."""

    model_config = ConfigDict(populate_by_name=True)

    session_id: str = Field(alias="sessionId")
    upload_url: Union[str, None] = Field(default=None, alias="uploadUrl")
    upload_id: Union[str, None] = Field(default=None, alias="uploadId")
    total_parts: Union[int, None] = Field(default=None, alias="totalParts")
    first_part_url: Union[str, None] = Field(default=None, alias="firstPartUrl")


class UploadProgress(BaseModel):
    """Progress information for an upload."""

    session_id: str
    bytes_uploaded: int
    total_bytes: int
    percentage: float
    current_part: Union[int, None] = None
    total_parts: Union[int, None] = None
