# generated by datamodel-codegen:
#   filename:  promptius-gui-schema.json
#   timestamp: 2025-12-23T10:19:28+00:00

from __future__ import annotations

from enum import Enum
from typing import List, Literal, Union

from pydantic import BaseModel, ConfigDict, Field, RootModel, conint, constr


class ButtonVariant(Enum):
    primary = 'primary'
    secondary = 'secondary'
    outline = 'outline'
    ghost = 'ghost'
    destructive = 'destructive'


class ButtonSize(Enum):
    sm = 'sm'
    md = 'md'
    lg = 'lg'


class InputType(Enum):
    text = 'text'
    email = 'email'
    password = 'password'
    number = 'number'
    tel = 'tel'
    url = 'url'
    search = 'search'
    date = 'date'


class InputSize(Enum):
    sm = 'sm'
    md = 'md'
    lg = 'lg'


class AlertVariant(Enum):
    info = 'info'
    success = 'success'
    warning = 'warning'
    error = 'error'


class TextTag(Enum):
    h1 = 'h1'
    h2 = 'h2'
    h3 = 'h3'
    h4 = 'h4'
    h5 = 'h5'
    h6 = 'h6'
    p = 'p'
    span = 'span'
    label = 'label'


class AlignText(Enum):
    left = 'left'
    center = 'center'
    right = 'right'
    justify = 'justify'


class FlexDirection(Enum):
    row = 'row'
    column = 'column'


class ChartType(Enum):
    bar = 'bar'
    line = 'line'
    pie = 'pie'


class EventType(Enum):
    onClick = 'onClick'
    onSubmit = 'onSubmit'
    onChange = 'onChange'
    onFocus = 'onFocus'
    onBlur = 'onBlur'


class Target(Enum):
    field_self = '_self'
    field_blank = '_blank'


class NavigateAction(BaseModel):
    type: Literal['navigate']
    url: constr(min_length=1) = Field(..., description='URL or route to navigate to')
    target: Target = Field(..., description='Navigation target window')


class SetStateAction(BaseModel):
    type: Literal['setState']
    key: constr(min_length=1) = Field(..., description='State key to update')
    value: Union[str, float, bool] = Field(..., description='Value to set')


class Method(Enum):
    POST = 'POST'
    PUT = 'PUT'
    PATCH = 'PATCH'


class SubmitFormAction(BaseModel):
    type: Literal['submitForm']
    endpoint: str = Field(..., description='API endpoint to submit to')
    method: Method = Field(..., description='HTTP method for form submission')


class ValidateAction(BaseModel):
    type: Literal['validate']
    rules: List[str] = Field(..., description='Validation rules')


class CustomAction(BaseModel):
    type: Literal['custom']
    handler: constr(min_length=1) = Field(
        ..., description='Name of custom handler function'
    )


EventAction = Union[
    NavigateAction,
    SetStateAction,
    SubmitFormAction,
    ValidateAction,
    CustomAction,
]


class ButtonProps(BaseModel):
    label: constr(min_length=1) = Field(..., description='Button text')
    variant: ButtonVariant
    size: ButtonSize
    disabled: bool
    fullWidth: bool
    loading: bool


class InputProps(BaseModel):
    placeholder: str = Field(..., description='Placeholder text')
    type: InputType
    size: InputSize
    disabled: bool
    required: bool
    label: str = Field(..., description='Input label')
    helperText: str = Field(..., description='Helper text below input')
    defaultValue: str = Field(..., description='Default input value')
    maxLength: conint(ge=1) = Field(..., description='Maximum input length')
    minLength: conint(ge=0) = Field(..., description='Minimum input length')


class TextareaProps(BaseModel):
    placeholder: str = Field(..., description='Placeholder text')
    rows: conint(ge=1, le=20) = Field(..., description='Number of textarea rows')
    disabled: bool
    required: bool
    label: str = Field(..., description='Textarea label')
    helperText: str = Field(..., description='Helper text below textarea')
    maxLength: conint(ge=1) = Field(..., description='Maximum textarea length')


class TextProps(BaseModel):
    content: str = Field(..., description='Text content')
    tag: TextTag
    align: AlignText
    bold: bool
    italic: bool
    color: constr(pattern=r'^(#[0-9A-Fa-f]{6}|[a-z\-]+)$') = Field(
        ..., description='Text color (hex or CSS color name)'
    )


class CardProps(BaseModel):
    title: str = Field(..., description='Card title')
    description: str = Field(..., description='Card description')
    elevation: conint(ge=0, le=5) = Field(..., description='Card elevation level')
    padding: conint(ge=0, le=64) = Field(..., description='Card padding in pixels')


class AlertProps(BaseModel):
    message: constr(min_length=1) = Field(..., description='Alert message')
    title: str = Field(..., description='Alert title')
    variant: AlertVariant
    dismissible: bool


class ContainerProps(BaseModel):
    maxWidth: conint(ge=320, le=1920) = Field(
        ..., description='Maximum container width in pixels'
    )
    padding: conint(ge=0, le=64) = Field(..., description='Container padding in pixels')
    centered: bool


class GridProps(BaseModel):
    columns: conint(ge=1, le=12) = Field(..., description='Number of columns')
    gap: conint(ge=0, le=64) = Field(..., description='Gap between items in pixels')
    responsive: bool = Field(..., description='Enable responsive behavior')


class Align(Enum):
    start = 'start'
    center = 'center'
    end = 'end'
    stretch = 'stretch'


class StackProps(BaseModel):
    direction: FlexDirection
    gap: conint(ge=0, le=64) = Field(..., description='Gap between items in pixels')
    align: Align = Field(..., description='Alignment of items')


class ChartSeries(BaseModel):
    name: str = Field(..., description='Series name')
    data: List[float] = Field(..., description='Series data points', min_length=1)


class AxisXProps(BaseModel):
    label: str = Field(..., description='X-axis label')
    ticks: List[str] = Field(..., description='X-axis tick labels')
    showGrid: bool


class AxisYProps(BaseModel):
    label: str = Field(..., description='Y-axis label')
    min: float = Field(..., description='Y-axis minimum value')
    max: float = Field(..., description='Y-axis maximum value')
    showGrid: bool


class ChartAnnotation(BaseModel):
    x: float = Field(..., description='X coordinate')
    y: float = Field(..., description='Y coordinate')
    label: str = Field(..., description='Annotation label')


class LegendPosition(Enum):
    top = 'top'
    right = 'right'
    bottom = 'bottom'
    left = 'left'


class ChartProps(BaseModel):
    chartType: ChartType = Field(..., description='Chart visualization type')
    width: conint(ge=100, le=4000) = Field(..., description='Chart width in pixels')
    height: conint(ge=100, le=4000) = Field(..., description='Chart height in pixels')
    labels: List[str] = Field(..., description='Chart category labels')
    series: List[ChartSeries] = Field(
        ..., description='Chart data series', min_length=1
    )
    colors: List[str] = Field(..., description='Custom chart colors')
    title: str = Field(..., description='Chart title')
    showLegend: bool
    legendPosition: LegendPosition
    xAxis: AxisXProps
    yAxis: AxisYProps
    annotations: List[ChartAnnotation] = Field(..., description='Chart annotations')


class ButtonNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['button']
    props: ButtonProps


class InputNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['input']
    props: InputProps


class TextareaNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['textarea']
    props: TextareaProps


class TextNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['text']
    props: TextProps


class CardNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['card']
    props: CardProps


class AlertNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['alert']
    props: AlertProps


class ContainerNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['container']
    props: ContainerProps


class GridNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['grid']
    props: GridProps


class StackNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['stack']
    props: StackProps


class ChartNode(BaseModel):
    id: constr(min_length=1) = Field(
        ...,
        description='Unique node identifier. This id must be unique across all nodes in the nodes array. It is used to reference this node in edges (as src or dest) and events (as nodeId). The rootId in metadata must match one of these ids.',
    )
    type: Literal['chart']
    props: ChartProps


Node = Union[
    ButtonNode,
    InputNode,
    TextareaNode,
    TextNode,
    CardNode,
    AlertNode,
    ContainerNode,
    GridNode,
    StackNode,
    ChartNode,
]


class Edge(BaseModel):
    src: constr(min_length=1) = Field(
        ...,
        description='The ID of the parent node. This MUST match the id of a node in the nodes array. The parent node will contain this child as a nested component.',
    )
    dest: constr(min_length=1) = Field(
        ...,
        description='The ID of the child node. This MUST match the id of a node in the nodes array. This child will be rendered inside the parent node (src).',
    )
    order: conint(ge=0) = Field(
        ...,
        description='The rendering order among sibling children. Lower numbers are rendered first. If multiple edges have the same parent (src), their children will be rendered in ascending order of this value.',
    )


class Event(BaseModel):
    nodeId: constr(min_length=1) = Field(
        ...,
        description='The ID of the node to bind this event to. This MUST match the id of a node in the nodes array. When the specified eventType occurs on this node, the associated action will be executed.',
    )
    eventType: EventType
    action: EventAction


class Framework(Enum):
    shadcn = 'shadcn'
    material_ui = 'material-ui'
    chakra_ui = 'chakra-ui'
    ant_design = 'ant-design'


class UIMetadata(BaseModel):
    title: constr(min_length=1) = Field(..., description='UI schema title')
    description: str = Field(..., description='UI schema description')
    version: constr(pattern=r'^\d+\.\d+\.\d+$') = Field(
        ..., description='Schema version'
    )
    framework: Framework = Field(..., description='Target UI framework')
    rootId: constr(min_length=1) = Field(
        ...,
        description='The ID of the root node that serves as the entry point for rendering the UI tree. This value MUST match the id field of exactly one node in the nodes array. The renderer will start building the UI hierarchy from this root node and traverse the edges to render child components in the specified order.',
    )


class PromptiusGuiSchema(BaseModel):
    metadata: UIMetadata
    nodes: List[Node] = Field(
        ...,
        description='Array of all UI component nodes. Each node represents a UI component (button, input, container, etc.) with a unique id. The rootId specified in metadata.rootId MUST exist as one of these node ids.',
        min_length=1,
    )
    edges: List[Edge] = Field(
        ...,
        description="Array of edges defining parent-child relationships in the component tree. Each edge connects a parent node (src) to a child node (dest) and specifies the rendering order (order). Edges define the hierarchical structure: nodes without incoming edges are top-level, and children are nested within their parent components. If a node has no edges pointing to it, it is an orphan and won't be rendered unless it's the root node.",
    )
    events: List[Event] = Field(
        ...,
        description='Array of event bindings that connect user interactions (onClick, onSubmit, onChange, etc.) to specific nodes. Each event specifies the nodeId (which MUST exist in the nodes array), the eventType, and the action to perform when the event is triggered.',
    )
