from __future__ import annotations

from datetime import date, datetime
from enum import StrEnum
from typing import Any
from uuid import UUID

from .model import AliasChoices, Field, Schema


class CommandPayload(Schema):
    aggregate_id: UUID | None = Field(default=None)
    command_type: str
    command_data: dict[str, Any] = Field(default_factory=dict)


class CreateTaskRequest(Schema):
    cr_ref: str
    tags: list[str] = Field(default_factory=list)
    message: str
    commands: list[CommandPayload]


class TaskResponse(Schema):
    id: int
    task_id: UUID
    created_by: UUID
    created_on: datetime
    resolved_by: UUID | None
    resolved_on: datetime | None
    last_updated_on: datetime | None
    last_updated_by: UUID | None
    status: str
    change_request_ref: str
    tags: list[str] = Field(default_factory=list)
    assignee: UUID | None
    message: str
    creation_message: str


class QueryRequest(Schema):
    item_type_id: UUID
    versions: list[str] = Field(default_factory=list)
    filters: list[dict[str, Any]] = Field(default_factory=list)
    filters_mode: str = Field(default="or")
    order_by: list[dict[str, Any]] = Field(default_factory=list)
    item_id: UUID | None = None
    limit: int | None = None
    offset: int | None = None
    version: str | None = None
    valid_at: date | None = None
    include_history: bool | None = False


class QueryResponseEntry(Schema):
    id: int
    item_id: UUID = Field(
        validation_alias=AliasChoices("itemId", "aggregateId", "aggregate_id"),
        serialization_alias="itemId",
    )
    version: str
    data: dict[str, Any] = Field(default_factory=dict)
    ref_properties: dict[str, Any] = Field(default_factory=dict)
    val_from: datetime
    val_to: datetime | None
    status: str | None
    release: int
    item_type_id: UUID
    task_uid: UUID | None


class QueryResponse(Schema):
    count: int
    data: list[QueryResponseEntry] = Field(default_factory=list)


class ItemRequest(Schema):
    item_type_id: UUID
    version: str = "default"
    aggregate_id: UUID = Field(
        validation_alias=AliasChoices("itemId", "aggregateId", "aggregate_id"),
        serialization_alias="itemId",
    )


class ItemDataResponse(ItemRequest):
    data: dict[str, Any] = Field(default_factory=dict)


class DependencyResponse(ItemDataResponse):
    step: int


class CatalogItemTypeResponse(Schema):
    item_type_id: UUID
    path: str


class ItemTypeVersionMetadataResponse(Schema):
    version: str
    description: str | None = None
    json_schema: dict[str, Any] = Field(default_factory=dict)


class ItemTypeMetadataResponse(Schema):
    name: str
    title: str | None = None
    ordinal: int | None = None
    collection_id: UUID
    item_type_id: UUID
    versions: list[ItemTypeVersionMetadataResponse] = Field(default_factory=list)


class ItemTypeDisplayAttributesResponse(Schema):
    item_type_id: UUID
    version: str
    display_attributes: list[str] = Field(default_factory=list)


class CommandTypes(StrEnum):
    ADD = "add"
    CREATE = "create"
    UPDATE = "update"
    RETIRE = "retire"
    REFRESH = "refresh"
    RETIRE_BULK = "retire_bulk"


class CommandDryRunRequest(Schema):
    command_uid: UUID | None = None
    item_id: UUID | None = None
    item_type_id: UUID
    version: str | None = None
    command_type: CommandTypes
    data: dict[str, Any] = Field(default_factory=dict)
    skip_nested_commands: bool = False


class ItemProjectionEventSchema(Schema):
    event_uid: UUID
    aggregate_id: UUID
    release: int | None = None
    task_uid: UUID | None = None
    event_type: str | None = None
    item_type_id: UUID | None = None
    version: str | None = None
    data: dict[str, Any] | None = None
    qfilter: list[Any] | dict[str, Any] | None = None


class CommandDryRunSchema(Schema):
    events: list[ItemProjectionEventSchema] = Field(default_factory=list)
    skip_events: list[ItemProjectionEventSchema] | None = None
    validation_errors: list[dict[str, Any]] | None = None
    graph: dict[str, Any] | None = None
    timestamp: datetime | None = None


class CommandDryRunResponseEntry(Schema):
    command_uid: UUID = Field(
        validation_alias=AliasChoices("commandUid", "commandId", "command_uid"),
        serialization_alias="commandUid",
    )
    dryrun: CommandDryRunSchema | None
    error: list[dict[str, Any]] | None


class CommandDryRunResponse(Schema):
    skip_nested_commands: bool = False
    commands: list[CommandDryRunResponseEntry] = Field(default_factory=list)


class ReportGenerationResponse(Schema):
    job_id: str


class ReportDownloadResponse(Schema):
    job_id: str
    file_name: str
    download_url: str


class BackgroundTaskStatus(Schema):
    job_id: str
    ready: bool
    failed: bool
    success: bool


class EventResponse(Schema):
    event_uid: UUID
    timestamp: datetime | None = None
    release: int | None = None
    event_type: str
    data: dict[str, Any] = Field(default_factory=dict)
    aggregate_id: UUID
    user_uid: UUID
    task_uid: UUID | None = None


__all__ = [
    "BackgroundTaskStatus",
    "CatalogItemTypeResponse",
    "CommandDryRunRequest",
    "CommandDryRunResponse",
    "CommandDryRunResponseEntry",
    "CommandDryRunSchema",
    "CommandPayload",
    "CommandTypes",
    "CreateTaskRequest",
    "DependencyResponse",
    "EventResponse",
    "ItemTypeDisplayAttributesResponse",
    "ItemTypeMetadataResponse",
    "ItemDataResponse",
    "ItemProjectionEventSchema",
    "ItemRequest",
    "ItemTypeVersionMetadataResponse",
    "QueryRequest",
    "QueryResponse",
    "QueryResponseEntry",
    "ReportDownloadResponse",
    "ReportGenerationResponse",
    "TaskResponse",
]
