"""
Form Field Pydantic Schemas - Merged Untitled UI + Payload CMS

Naming: Untitled UI style (camelCase, descriptive)
Features: Payload style (conditions, admin, validation, hooks)

Source: lightwave/schema/definitions/ui/forms/fields.yaml
"""

from __future__ import annotations

from typing import Annotated, Any, Literal, Union

from pydantic import BaseModel, ConfigDict, Field

# =============================================================================
# TYPE LITERALS
# =============================================================================

FieldType = Literal[
    "text",
    "number",
    "select",
    "checkbox",
    "radio",
    "textarea",
    "date",
    "email",
    "password",
    "upload",
    "richText",
    "array",
    "group",
    "blocks",
]

FieldSize = Literal["sm", "md", "lg"]
IconPosition = Literal["leading", "trailing"]
AdminPosition = Literal["main", "sidebar"]
ConditionOperator = Literal["equals", "not_equals", "contains", "exists", "not_exists"]
RadioLayout = Literal["horizontal", "vertical"]
DatePickerType = Literal["date", "datetime", "time", "month", "year"]
RichTextEditor = Literal["lexical", "slate", "tiptap"]
RichTextFeature = Literal[
    "bold",
    "italic",
    "underline",
    "strikethrough",
    "code",
    "link",
    "list",
    "heading",
    "quote",
    "image",
    "video",
    "table",
]
InputMode = Literal["text", "email", "tel", "url", "search", "numeric", "decimal"]


# =============================================================================
# SUPPORTING TYPES
# =============================================================================


class SelectOption(BaseModel):
    """Option for select/radio fields."""

    value: str
    label: str

    model_config = ConfigDict(extra="forbid")


class FieldCondition(BaseModel):
    """Conditional display based on other field values (Payload style)."""

    field: str = Field(description="Field name to check")
    operator: ConditionOperator = Field(default="equals")
    value: Any = Field(default=None, description="Value to compare against")

    model_config = ConfigDict(extra="forbid")


class FieldAdmin(BaseModel):
    """Admin panel configuration (Payload style with Untitled UI naming)."""

    description: str | None = Field(default=None, description="Extended description shown in admin")
    position: AdminPosition = Field(default="main", description="Field position in admin form")
    width: str | None = Field(default=None, description="Field width (e.g., '50%')")
    style: dict[str, Any] | None = Field(default=None, description="Custom CSS styles")
    components: dict[str, str] | None = Field(default=None, description="Custom component overrides")
    # List view controls (Payload style)
    disableListColumn: bool = Field(
        default=False,
        serialization_alias="disableListColumn",
        description="Hide from list view columns",
    )
    disableListFilter: bool = Field(
        default=False,
        serialization_alias="disableListFilter",
        description="Hide from list view filters",
    )
    disableGroupBy: bool = Field(
        default=False,
        serialization_alias="disableGroupBy",
        description="Hide from groupBy options",
    )
    disableBulkEdit: bool = Field(
        default=False,
        serialization_alias="disableBulkEdit",
        description="Disable bulk editing",
    )

    model_config = ConfigDict(extra="forbid", populate_by_name=True)


class FieldHooks(BaseModel):
    """Field lifecycle hooks (Payload style)."""

    beforeValidate: list[str] | None = Field(default=None, serialization_alias="beforeValidate")
    beforeChange: list[str] | None = Field(default=None, serialization_alias="beforeChange")
    afterChange: list[str] | None = Field(default=None, serialization_alias="afterChange")
    afterRead: list[str] | None = Field(default=None, serialization_alias="afterRead")

    model_config = ConfigDict(extra="forbid", populate_by_name=True)


class FieldAccess(BaseModel):
    """Field-level access control (Payload style)."""

    create: bool | None = Field(default=None, description="Can create with this field")
    read: bool | None = Field(default=None, description="Can read this field")
    update: bool | None = Field(default=None, description="Can update this field")

    model_config = ConfigDict(extra="forbid")


# =============================================================================
# BASE FIELD
# =============================================================================


class FieldBase(BaseModel):
    """
    Base properties for all form fields.

    Naming: Untitled UI conventions (hint, tooltip, size, etc.)
    Features: Payload CMS functionality (localized, unique, virtual, hooks, etc.)
    """

    # Identity (required)
    name: str = Field(description="Unique field identifier")

    # Display (Untitled UI naming)
    label: str | None = Field(default=None, description="Label displayed above field")
    hint: str | None = Field(default=None, description="Helper text below field (Untitled UI: hint)")
    placeholder: str | None = Field(default=None, description="Placeholder text")
    tooltip: str | None = Field(default=None, description="Tooltip on hover (Untitled UI)")
    tooltipDescription: str | None = Field(
        default=None,
        serialization_alias="tooltipDescription",
        description="Extended tooltip description",
    )

    # Visual (Untitled UI naming)
    size: FieldSize = Field(default="sm", description="Field size variant")
    icon: str | None = Field(default=None, description="Icon component name")
    iconPosition: IconPosition = Field(
        default="leading",
        serialization_alias="iconPosition",
        description="Icon position",
    )
    className: str | None = Field(default=None, serialization_alias="className", description="Custom CSS class")
    inputClassName: str | None = Field(
        default=None,
        serialization_alias="inputClassName",
        description="Input element CSS class",
    )
    wrapperClassName: str | None = Field(
        default=None,
        serialization_alias="wrapperClassName",
        description="Wrapper CSS class",
    )

    # State
    required: bool = Field(default=False, description="Whether field is required")
    disabled: bool = Field(default=False, description="Whether field is disabled")
    readOnly: bool = Field(default=False, serialization_alias="readOnly", description="Whether read-only")
    hidden: bool = Field(default=False, description="Whether field is hidden")

    # Validation
    validation_rules: dict[str, Any] | None = Field(
        default=None,
        serialization_alias="validate",
        description="Custom validation rules",
    )
    minLength: int | None = Field(default=None, serialization_alias="minLength", description="Minimum length")
    maxLength: int | None = Field(default=None, serialization_alias="maxLength", description="Maximum length")
    pattern: str | None = Field(default=None, description="Regex validation pattern")

    # Values
    defaultValue: Any | None = Field(default=None, serialization_alias="defaultValue", description="Default value")

    # Payload-style Features
    localized: bool = Field(default=False, description="Supports localization (Payload)")
    unique: bool = Field(default=False, description="Value must be unique (Payload)")
    index: bool = Field(default=False, description="Index in database (Payload)")
    virtual: bool = Field(default=False, description="Virtual field not stored (Payload)")

    # Complex nested (Payload style)
    admin: FieldAdmin | None = Field(default=None, description="Admin configuration")
    hooks: FieldHooks | None = Field(default=None, description="Lifecycle hooks")
    access: FieldAccess | None = Field(default=None, description="Access control")
    condition: FieldCondition | None = Field(default=None, description="Conditional display")

    model_config = ConfigDict(extra="forbid", populate_by_name=True)


# =============================================================================
# SPECIFIC FIELD TYPES
# =============================================================================


class TextField(FieldBase):
    """Single-line text input."""

    type: Literal["text"] = Field(default="text")
    hasMany: bool = Field(
        default=False,
        serialization_alias="hasMany",
        description="Allow multiple values",
    )
    shortcut: str | None = Field(default=None, description="Keyboard shortcut hint (Untitled UI)")
    autoComplete: str | None = Field(
        default=None,
        serialization_alias="autoComplete",
        description="HTML autocomplete attribute",
    )
    inputMode: InputMode | None = Field(
        default=None,
        serialization_alias="inputMode",
        description="Mobile keyboard type",
    )


class NumberField(FieldBase):
    """Numeric input field."""

    type: Literal["number"] = Field(default="number")
    min: float | None = Field(default=None, description="Minimum value")
    max: float | None = Field(default=None, description="Maximum value")
    step: float | None = Field(default=None, description="Step increment")
    hasMany: bool = Field(default=False, serialization_alias="hasMany", description="Allow multiple")
    prefix: str | None = Field(default=None, description="Prefix text (e.g., '$')")
    suffix: str | None = Field(default=None, description="Suffix text (e.g., 'USD')")


class SelectField(FieldBase):
    """Dropdown select field."""

    type: Literal["select"] = Field(default="select")
    options: list[SelectOption] = Field(description="Available options")
    hasMany: bool = Field(
        default=False,
        serialization_alias="hasMany",
        description="Allow multiple selections",
    )
    isClearable: bool = Field(
        default=False,
        serialization_alias="isClearable",
        description="Allow clearing selection",
    )
    isSearchable: bool = Field(
        default=False,
        serialization_alias="isSearchable",
        description="Enable search filtering",
    )


class CheckboxField(FieldBase):
    """Boolean checkbox field."""

    type: Literal["checkbox"] = Field(default="checkbox")


class RadioField(FieldBase):
    """Radio button group."""

    type: Literal["radio"] = Field(default="radio")
    options: list[SelectOption] = Field(description="Available options")
    layout: RadioLayout = Field(default="vertical", description="Layout direction")


class TextareaField(FieldBase):
    """Multi-line text input."""

    type: Literal["textarea"] = Field(default="textarea")
    rows: int = Field(default=3, description="Number of visible rows")
    autoResize: bool = Field(
        default=False,
        serialization_alias="autoResize",
        description="Auto-resize based on content",
    )


class DateField(FieldBase):
    """Date/time picker."""

    type: Literal["date"] = Field(default="date")
    pickerType: DatePickerType = Field(
        default="date",
        serialization_alias="pickerType",
        description="Type of date picker",
    )
    minDate: str | None = Field(
        default=None,
        serialization_alias="minDate",
        description="Minimum selectable date",
    )
    maxDate: str | None = Field(
        default=None,
        serialization_alias="maxDate",
        description="Maximum selectable date",
    )
    displayFormat: str | None = Field(
        default=None,
        serialization_alias="displayFormat",
        description="Date display format",
    )


class EmailField(FieldBase):
    """Email input with validation."""

    type: Literal["email"] = Field(default="email")
    autoComplete: str = Field(default="email", serialization_alias="autoComplete", description="Autocomplete")


class PasswordField(FieldBase):
    """Password input with toggle visibility."""

    type: Literal["password"] = Field(default="password")
    showToggle: bool = Field(
        default=True,
        serialization_alias="showToggle",
        description="Show visibility toggle",
    )
    strengthIndicator: bool = Field(
        default=False,
        serialization_alias="strengthIndicator",
        description="Show strength indicator",
    )


class UploadField(FieldBase):
    """File upload field."""

    type: Literal["upload"] = Field(default="upload")
    relationTo: str | None = Field(
        default=None,
        serialization_alias="relationTo",
        description="Collection to upload to",
    )
    hasMany: bool = Field(default=False, serialization_alias="hasMany", description="Allow multiple")
    mimeTypes: list[str] | None = Field(default=None, serialization_alias="mimeTypes", description="Allowed MIME types")
    maxSize: int | None = Field(default=None, serialization_alias="maxSize", description="Max file size bytes")


class RichTextField(FieldBase):
    """Rich text editor (WYSIWYG)."""

    type: Literal["richText"] = Field(default="richText")
    editor: RichTextEditor = Field(default="lexical", description="Editor engine")
    features: list[RichTextFeature] | None = Field(default=None, description="Enabled formatting features")


class ArrayField(FieldBase):
    """Repeatable array of fields."""

    type: Literal["array"] = Field(default="array")
    fields: list["FormField"] = Field(description="Fields within each item")
    minRows: int | None = Field(default=None, serialization_alias="minRows", description="Minimum rows")
    maxRows: int | None = Field(default=None, serialization_alias="maxRows", description="Maximum rows")
    labels: dict[str, str] | None = Field(default=None, description="singular/plural labels")


class GroupField(FieldBase):
    """Group of related fields."""

    type: Literal["group"] = Field(default="group")
    fields: list["FormField"] = Field(description="Fields within group")


class BlockDefinition(BaseModel):
    """Block type definition for BlocksField."""

    slug: str = Field(description="Unique block identifier")
    labels: dict[str, str] | None = Field(default=None, description="singular/plural labels")
    fields: list["FormField"] = Field(description="Fields within block")
    imageUrl: str | None = Field(default=None, serialization_alias="imageUrl", description="Preview image URL")
    imageAltText: str | None = Field(
        default=None,
        serialization_alias="imageAltText",
        description="Preview image alt text",
    )

    model_config = ConfigDict(extra="forbid", populate_by_name=True)


class BlocksField(FieldBase):
    """Block-based content editor."""

    type: Literal["blocks"] = Field(default="blocks")
    blocks: list[BlockDefinition] = Field(description="Available block types")
    minRows: int | None = Field(default=None, serialization_alias="minRows", description="Minimum blocks")
    maxRows: int | None = Field(default=None, serialization_alias="maxRows", description="Maximum blocks")


# =============================================================================
# FIELD UNION TYPE
# =============================================================================

# Note: Named FormField to avoid collision with Pydantic's Field function
FormField = Annotated[
    Union[
        TextField,
        NumberField,
        SelectField,
        CheckboxField,
        RadioField,
        TextareaField,
        DateField,
        EmailField,
        PasswordField,
        UploadField,
        RichTextField,
        ArrayField,
        GroupField,
        BlocksField,
    ],
    Field(discriminator="type"),
]

# Alias for convenience (matches TypeScript naming)
Field_ = FormField

# Update forward references for recursive types
ArrayField.model_rebuild()
GroupField.model_rebuild()
BlockDefinition.model_rebuild()
BlocksField.model_rebuild()
