import uuid
from datetime import datetime
from typing import Literal

from pydantic import BaseModel, ConfigDict, model_validator

from app.schemas.navigation import PageBlockDef
from app.schemas.workflow import FormFieldDef

ComponentKind = Literal["page_block", "form_field"]


class ComponentCreate(BaseModel):
    kind: ComponentKind
    name: str
    description: str | None = None
    # Always an array so both kinds share one column/field shape — a
    # "page_block" component holds exactly the one selected block (with its
    # full children/groups subtree already inside it); a "form_field"
    # component holds one or more fields in canvas order. Validated below
    # against the real PageBlockDef/FormFieldDef schema per kind, same as
    # PageCreate/FormCreate validate their own JSONB block/field lists.
    definition: list[dict]

    @model_validator(mode="after")
    def _validate_definition(self) -> "ComponentCreate":
        if self.kind == "page_block":
            if len(self.definition) != 1:
                raise ValueError("A page_block component must contain exactly one root block.")
            PageBlockDef.model_validate(self.definition[0])
        else:
            if not self.definition:
                raise ValueError("A form_field component must contain at least one field.")
            for field in self.definition:
                FormFieldDef.model_validate(field)
        return self


class ComponentUpdate(BaseModel):
    # `definition` is intentionally not editable here — to change a saved
    # component's contents, delete it and save a fresh one from the canvas.
    # Keeps this the same simple "rename/re-describe" shape as most other
    # entities' Update schemas, with no re-validation-of-a-partial-JSONB-
    # array edge case to handle.
    name: str | None = None
    description: str | None = None


class ComponentRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)
    id: uuid.UUID
    tenant_id: uuid.UUID
    kind: ComponentKind
    name: str
    description: str | None
    definition: list[dict]
    created_at: datetime
    updated_at: datetime
