/**
 * Auto-generated Zod schemas for Kumo components
 * DO NOT EDIT - Generated by scripts/component-registry/index.ts
 *
 * These schemas enable runtime validation of AI-generated UI trees.
 */

import { z } from "zod";

// SafeParseReturnType was removed in Zod v4, but we still want stable typing.
export type SafeParseResult<T> =
  | { success: true; data: T; error?: never }
  | { success: false; error: z.ZodError<any>; data?: never };

// =============================================================================
// Dynamic Value Schema (for data binding)
// =============================================================================

/**
 * A value that can either be a literal or a reference to the data model.
 * Example: "Hello" or { path: "/user/name" }
 */
export const DynamicValueSchema = z.union([
  z.string(),
  z.number(),
  z.boolean(),
  z.null(),
  z.object({ path: z.string() }),
]);

export type DynamicValue<T = unknown> = T | { path: string };

// =============================================================================
// Visibility Condition Schemas
// =============================================================================

/**
 * Visibility conditions for conditional rendering.
 * Components can be shown/hidden based on data, auth, or logic expressions.
 */

// Forward declaration for recursive types
// Note: Numeric comparisons use DynamicValue (not DynamicValue<number>) for Zod compatibility
export type LogicExpression =
  | { and: LogicExpression[] }
  | { or: LogicExpression[] }
  | { not: LogicExpression }
  | { path: string }
  | { eq: [DynamicValue, DynamicValue] }
  | { neq: [DynamicValue, DynamicValue] }
  | { gt: [DynamicValue, DynamicValue] }
  | { gte: [DynamicValue, DynamicValue] }
  | { lt: [DynamicValue, DynamicValue] }
  | { lte: [DynamicValue, DynamicValue] };

// Lazy schema for recursive logic expressions
const LogicExpressionSchema: z.ZodType<LogicExpression> = z.lazy(() =>
  z.union([
    z.object({ and: z.array(LogicExpressionSchema) }),
    z.object({ or: z.array(LogicExpressionSchema) }),
    z.object({ not: LogicExpressionSchema }),
    z.object({ path: z.string() }),
    z.object({ eq: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
    z.object({ neq: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
    z.object({ gt: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
    z.object({ gte: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
    z.object({ lt: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
    z.object({ lte: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
  ])
);

export const VisibilityConditionSchema = z.union([
  z.boolean(),
  z.object({ path: z.string() }),
  z.object({ auth: z.enum(["signedIn", "signedOut"]) }),
  LogicExpressionSchema,
]);

export type VisibilityCondition = z.infer<typeof VisibilityConditionSchema>;

// =============================================================================
// Action Schemas
// =============================================================================

/**
 * Action confirmation dialog configuration
 */
export const ActionConfirmSchema = z.object({
  title: z.string(),
  message: z.string(),
  variant: z.enum(["default", "danger"]).optional(),
  confirmLabel: z.string().optional(),
  cancelLabel: z.string().optional(),
});

/**
 * Action definition that AI can declare
 */
export const ActionSchema = z.object({
  name: z.string(),
  params: z.record(z.string(), DynamicValueSchema).optional(),
  confirm: ActionConfirmSchema.optional(),
  onSuccess: z.object({ set: z.record(z.string(), DynamicValueSchema) }).optional(),
  onError: z.object({ set: z.record(z.string(), DynamicValueSchema) }).optional(),
});

export type Action = z.infer<typeof ActionSchema>;

// =============================================================================
// Component Props Schemas
// =============================================================================

export const BadgePropsSchema = z.object({
  variant: z.enum(["primary", "secondary", "destructive", "success", "outline", "beta"]).optional(), // Visual style of the badge. - `"primary"` — High-emphasis badge for important labels - `"secondary"` — Subtle badge for secondary information - `"destructive"` — Error or danger state indicator - `"outline"` — Bordered badge with transparent background - `"beta"` — Dashed-border badge for beta/experimental features
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Content rendered inside the badge.
});

export const BannerPropsSchema = z.object({
  icon: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Icon element rendered before the banner content (e.g. from `@phosphor-icons/react`).
  title: z.string().optional(), // Primary heading text for the banner. Use for i18n string injection.
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Secondary description text displayed below the title. Use for i18n string injection.
  text: z.string().optional(),
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  variant: z.enum(["default", "alert", "error"]).optional(), // Visual style of the banner. - `"default"` — Informational blue banner for general messages - `"alert"` — Warning yellow banner for cautionary messages - `"error"` — Error red banner for critical issues
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
});

export const BreadcrumbsPropsSchema = z.object({
  size: z.enum(["sm", "base"]).optional(), // Size of the breadcrumbs. - `"sm"` — Compact breadcrumbs for dense UIs - `"base"` — Default breadcrumbs size
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
});

export const ButtonPropsSchema = z.object({
  shape: z.enum(["base", "square", "circle"]).optional(),
  size: z.enum(["xs", "sm", "base", "lg"]).optional(),
  variant: z.enum(["primary", "secondary", "ghost", "destructive", "secondary-destructive", "outline"]).optional(),
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  className: z.string().optional(),
  icon: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Icon from `@phosphor-icons/react` or a React element. Rendered before children.
  loading: z.boolean().optional(), // Shows a loading spinner and disables interaction.
  id: z.string().optional(),
  lang: z.string().optional(),
  title: z.string().optional(),
  disabled: z.boolean().optional(),
  name: z.string().optional(),
  type: z.enum(["submit", "reset", "button"]).optional(),
  value: z.unknown().optional(),
});

export const CheckboxPropsSchema = z.object({
  variant: z.enum(["default", "error"]).optional(), // Visual variant: "default" or "error" for validation failures (visual only, no error text)
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Label content for the checkbox (enables built-in Field wrapper) - can be a string or any React node
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content to display next to the label via an info icon
  controlFirst: z.boolean().optional(), // When true (default), checkbox appears before label. When false, label appears before checkbox.
  checked: z.boolean().optional(), // Whether the checkbox is checked (controlled)
  indeterminate: z.boolean().optional(), // Whether the checkbox is in indeterminate state
  disabled: z.boolean().optional(), // Whether the checkbox is disabled
  name: z.string().optional(), // Name for form submission
  required: z.boolean().optional(), // Whether the field is required
  className: z.string().optional(), // Additional class name
  onValueChange: z.unknown().optional(), // Callback when checkbox value changes
});

export const ClipboardTextPropsSchema = z.object({
  size: z.enum(["sm", "base", "lg"]).optional(), // Size of the clipboard text field. - `"sm"` — Small clipboard text for compact UIs - `"base"` — Default clipboard text size - `"lg"` — Large clipboard text for prominent display
  text: z.string(), // The text to display and copy to clipboard.
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  tooltip: z.unknown().optional(), // Tooltip config. Shows tooltip on hover, anchored toast on click.
  labels: z.unknown().optional(), // Accessible labels for i18n.
});

export const CloudflareLogoPropsSchema = z.object({
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  className: z.string().optional(),
  height: z.unknown().optional(),
  id: z.string().optional(),
  lang: z.string().optional(),
  media: z.string().optional(),
  method: z.string().optional(),
  name: z.string().optional(),
  target: z.string().optional(),
  type: z.string().optional(),
  width: z.unknown().optional(),
  accentHeight: z.unknown().optional(),
  accumulate: z.enum(["none", "sum"]).optional(),
  additive: z.enum(["replace", "sum"]).optional(),
  alignmentBaseline: z.enum(["auto", "baseline", "before-edge", "text-before-edge", "middle", "central", "after-edge", "text-after-edge", "ideographic", "alphabetic", "hanging", "mathematical", "inherit"]).optional(),
  allowReorder: z.enum(["no", "yes"]).optional(),
  alphabetic: z.unknown().optional(),
  amplitude: z.unknown().optional(),
  arabicForm: z.enum(["initial", "medial", "terminal", "isolated"]).optional(),
  ascent: z.unknown().optional(),
  attributeName: z.string().optional(),
  attributeType: z.string().optional(),
  autoReverse: z.unknown().optional(),
  azimuth: z.unknown().optional(),
  baseFrequency: z.unknown().optional(),
  baselineShift: z.unknown().optional(),
  baseProfile: z.unknown().optional(),
  bbox: z.unknown().optional(),
  begin: z.unknown().optional(),
  bias: z.unknown().optional(),
  by: z.unknown().optional(),
  calcMode: z.unknown().optional(),
  capHeight: z.unknown().optional(),
  clip: z.unknown().optional(),
  clipPath: z.string().optional(),
  clipPathUnits: z.unknown().optional(),
  clipRule: z.unknown().optional(),
  colorInterpolation: z.unknown().optional(),
  colorInterpolationFilters: z.enum(["auto", "sRGB", "linearRGB", "inherit"]).optional(),
  colorProfile: z.unknown().optional(),
  colorRendering: z.unknown().optional(),
  contentScriptType: z.unknown().optional(),
  contentStyleType: z.unknown().optional(),
  cursor: z.unknown().optional(),
  cx: z.unknown().optional(),
  cy: z.unknown().optional(),
  d: z.string().optional(),
  decelerate: z.unknown().optional(),
  descent: z.unknown().optional(),
  diffuseConstant: z.unknown().optional(),
  direction: z.unknown().optional(),
  display: z.unknown().optional(),
  divisor: z.unknown().optional(),
  dominantBaseline: z.enum(["auto", "use-script", "no-change", "reset-size", "ideographic", "alphabetic", "hanging", "mathematical", "central", "middle", "text-after-edge", "text-before-edge", "inherit"]).optional(),
  dur: z.unknown().optional(),
  dx: z.unknown().optional(),
  dy: z.unknown().optional(),
  edgeMode: z.unknown().optional(),
  elevation: z.unknown().optional(),
  enableBackground: z.unknown().optional(),
  end: z.unknown().optional(),
  exponent: z.unknown().optional(),
  externalResourcesRequired: z.unknown().optional(),
  fill: z.string().optional(),
  fillOpacity: z.unknown().optional(),
  fillRule: z.enum(["nonzero", "evenodd", "inherit"]).optional(),
  filter: z.string().optional(),
  filterRes: z.unknown().optional(),
  filterUnits: z.unknown().optional(),
  floodColor: z.unknown().optional(),
  floodOpacity: z.unknown().optional(),
  focusable: z.unknown().optional(),
  fontFamily: z.string().optional(),
  fontSize: z.unknown().optional(),
  fontSizeAdjust: z.unknown().optional(),
  fontStretch: z.unknown().optional(),
  fontStyle: z.unknown().optional(),
  fontVariant: z.unknown().optional(),
  fontWeight: z.unknown().optional(),
  format: z.unknown().optional(),
  fr: z.unknown().optional(),
  from: z.unknown().optional(),
  fx: z.unknown().optional(),
  fy: z.unknown().optional(),
  g1: z.unknown().optional(),
  g2: z.unknown().optional(),
  glyphName: z.unknown().optional(),
  glyphOrientationHorizontal: z.unknown().optional(),
  glyphOrientationVertical: z.unknown().optional(),
  glyphRef: z.unknown().optional(),
  gradientTransform: z.string().optional(),
  gradientUnits: z.string().optional(),
  hanging: z.unknown().optional(),
  horizAdvX: z.unknown().optional(),
  horizOriginX: z.unknown().optional(),
  href: z.string().optional(),
  ideographic: z.unknown().optional(),
  imageRendering: z.unknown().optional(),
  in2: z.unknown().optional(),
  in: z.string().optional(),
  intercept: z.unknown().optional(),
  k1: z.unknown().optional(),
  k2: z.unknown().optional(),
  k3: z.unknown().optional(),
  k4: z.unknown().optional(),
  k: z.unknown().optional(),
  kernelMatrix: z.unknown().optional(),
  kernelUnitLength: z.unknown().optional(),
  kerning: z.unknown().optional(),
  keyPoints: z.unknown().optional(),
  keySplines: z.unknown().optional(),
  keyTimes: z.unknown().optional(),
  lengthAdjust: z.unknown().optional(),
  letterSpacing: z.unknown().optional(),
  lightingColor: z.unknown().optional(),
  limitingConeAngle: z.unknown().optional(),
  local: z.unknown().optional(),
  markerEnd: z.string().optional(),
  markerHeight: z.unknown().optional(),
  markerMid: z.string().optional(),
  markerStart: z.string().optional(),
  markerUnits: z.unknown().optional(),
  markerWidth: z.unknown().optional(),
  mask: z.string().optional(),
  maskContentUnits: z.unknown().optional(),
  maskUnits: z.unknown().optional(),
  mathematical: z.unknown().optional(),
  mode: z.unknown().optional(),
  numOctaves: z.unknown().optional(),
  offset: z.unknown().optional(),
  opacity: z.unknown().optional(),
  operator: z.unknown().optional(),
  order: z.unknown().optional(),
  orient: z.unknown().optional(),
  orientation: z.unknown().optional(),
  origin: z.unknown().optional(),
  overflow: z.unknown().optional(),
  overlinePosition: z.unknown().optional(),
  overlineThickness: z.unknown().optional(),
  paintOrder: z.unknown().optional(),
  panose1: z.unknown().optional(),
  path: z.string().optional(),
  pathLength: z.unknown().optional(),
  patternContentUnits: z.string().optional(),
  patternTransform: z.unknown().optional(),
  patternUnits: z.string().optional(),
  pointerEvents: z.unknown().optional(),
  points: z.string().optional(),
  pointsAtX: z.unknown().optional(),
  pointsAtY: z.unknown().optional(),
  pointsAtZ: z.unknown().optional(),
  preserveAlpha: z.unknown().optional(),
  preserveAspectRatio: z.string().optional(),
  primitiveUnits: z.unknown().optional(),
  r: z.unknown().optional(),
  radius: z.unknown().optional(),
  refX: z.unknown().optional(),
  refY: z.unknown().optional(),
  renderingIntent: z.unknown().optional(),
  repeatCount: z.unknown().optional(),
  repeatDur: z.unknown().optional(),
  requiredExtensions: z.unknown().optional(),
  requiredFeatures: z.unknown().optional(),
  restart: z.unknown().optional(),
  result: z.string().optional(),
  rotate: z.unknown().optional(),
  rx: z.unknown().optional(),
  ry: z.unknown().optional(),
  scale: z.unknown().optional(),
  seed: z.unknown().optional(),
  shapeRendering: z.unknown().optional(),
  slope: z.unknown().optional(),
  spacing: z.unknown().optional(),
  specularConstant: z.unknown().optional(),
  specularExponent: z.unknown().optional(),
  speed: z.unknown().optional(),
  spreadMethod: z.string().optional(),
  startOffset: z.unknown().optional(),
  stdDeviation: z.unknown().optional(),
  stemh: z.unknown().optional(),
  stemv: z.unknown().optional(),
  stitchTiles: z.unknown().optional(),
  stopColor: z.string().optional(),
  stopOpacity: z.unknown().optional(),
  strikethroughPosition: z.unknown().optional(),
  strikethroughThickness: z.unknown().optional(),
  string: z.unknown().optional(),
  stroke: z.string().optional(),
  strokeDasharray: z.unknown().optional(),
  strokeDashoffset: z.unknown().optional(),
  strokeLinecap: z.enum(["butt", "round", "square", "inherit"]).optional(),
  strokeLinejoin: z.enum(["miter", "round", "bevel", "inherit"]).optional(),
  strokeMiterlimit: z.unknown().optional(),
  strokeOpacity: z.unknown().optional(),
  strokeWidth: z.unknown().optional(),
  surfaceScale: z.unknown().optional(),
  systemLanguage: z.unknown().optional(),
  tableValues: z.unknown().optional(),
  targetX: z.unknown().optional(),
  targetY: z.unknown().optional(),
  textAnchor: z.enum(["start", "middle", "end", "inherit"]).optional(),
  textDecoration: z.unknown().optional(),
  textLength: z.unknown().optional(),
  textRendering: z.unknown().optional(),
  to: z.unknown().optional(),
  transform: z.string().optional(),
  u1: z.unknown().optional(),
  u2: z.unknown().optional(),
  underlinePosition: z.unknown().optional(),
  underlineThickness: z.unknown().optional(),
  unicode: z.unknown().optional(),
  unicodeBidi: z.unknown().optional(),
  unicodeRange: z.unknown().optional(),
  unitsPerEm: z.unknown().optional(),
  vAlphabetic: z.unknown().optional(),
  values: z.string().optional(),
  vectorEffect: z.unknown().optional(),
  version: z.string().optional(),
  vertAdvY: z.unknown().optional(),
  vertOriginX: z.unknown().optional(),
  vertOriginY: z.unknown().optional(),
  vHanging: z.unknown().optional(),
  vIdeographic: z.unknown().optional(),
  viewBox: z.string().optional(),
  viewTarget: z.unknown().optional(),
  visibility: z.unknown().optional(),
  vMathematical: z.unknown().optional(),
  widths: z.unknown().optional(),
  wordSpacing: z.unknown().optional(),
  writingMode: z.unknown().optional(),
  x1: z.unknown().optional(),
  x2: z.unknown().optional(),
  x: z.unknown().optional(),
  xChannelSelector: z.string().optional(),
  xHeight: z.unknown().optional(),
  xlinkActuate: z.string().optional(),
  xlinkArcrole: z.string().optional(),
  xlinkHref: z.string().optional(),
  xlinkRole: z.string().optional(),
  xlinkShow: z.string().optional(),
  xlinkTitle: z.string().optional(),
  xlinkType: z.string().optional(),
  xmlBase: z.string().optional(),
  xmlLang: z.string().optional(),
  xmlns: z.string().optional(),
  xmlnsXlink: z.string().optional(),
  xmlSpace: z.string().optional(),
  y1: z.unknown().optional(),
  y2: z.unknown().optional(),
  y: z.unknown().optional(),
  yChannelSelector: z.string().optional(),
  z: z.unknown().optional(),
  zoomAndPan: z.string().optional(),
  variant: z.enum(["glyph", "full"]).optional(), // Logo variant - `glyph`: Cloud icon only - `full`: Cloud icon with "CLOUDFLARE" wordmark below
});

export const CodePropsSchema = z.object({
  lang: z.enum(["ts", "tsx", "jsonc", "bash", "css"]).optional(), // Language hint for the code content. - `"ts"` — TypeScript code - `"tsx"` — TypeScript JSX code - `"jsonc"` — JSON with comments - `"bash"` — Shell/Bash commands - `"css"` — CSS styles
  code: z.string(), // The code string to display.
  values: z.unknown().optional(), // Template values for `{{key}}` interpolation. Values with `highlight: true` are visually emphasized.
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
});

export const CollapsiblePropsSchema = z.object({
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  label: z.string(), // Text label displayed in the trigger button
  open: z.boolean().optional(), // Whether the collapsible content is visible
  className: z.string().optional(), // Additional CSS classes for the content panel
  onOpenChange: z.unknown().optional(), // Callback when collapsed state changes
});

export const ComboboxPropsSchema = z.object({
  size: z.enum(["xs", "sm", "base", "lg"]).optional(), // Size of the combobox trigger. Matches Input component sizes. - `"xs"` — Extra small for compact UIs (h-5 / 20px) - `"sm"` — Small for secondary fields (h-6.5 / 26px) - `"base"` — Default size (h-9 / 36px) - `"lg"` — Large for prominent fields (h-10 / 40px)
  inputSide: z.enum(["right", "top"]).optional(), // Position of the text input relative to chips in multi-select mode. - `"right"` — Input inline to the right of chips - `"top"` — Input above chips
  items: z.array(z.unknown()), // Array of items to display in the dropdown
  value: z.array(z.unknown()).optional(), // Currently selected value(s)
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Combobox content (trigger, content, items)
  className: z.string().optional(), // Additional CSS classes
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Label content for the combobox (enables Field wrapper) - can be a string or any React node
  required: z.boolean().optional(), // Whether the combobox is required
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content to display next to the label via an info icon
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Helper text displayed below the combobox
  error: z.unknown().optional(), // Error message or validation error object
  onValueChange: z.unknown().optional(), // Callback when selection changes
  multiple: z.boolean().optional(), // Allow multiple selections
  isItemEqualToValue: z.unknown().optional(), // Custom equality function for comparing items
});

export const CommandPalettePropsSchema = z.object({
  open: z.boolean(), // Whether the dialog is open
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Child content - typically one or more Panel components
});

export const DatePickerPropsSchema = z.object({
  className: z.string().optional(), // Additional CSS classes
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Child elements
});

export const DateRangePickerPropsSchema = z.object({
  size: z.enum(["sm", "base", "lg"]).optional(), // Calendar size. - `"sm"` — Compact calendar for tight spaces - `"base"` — Default calendar size - `"lg"` — Large calendar for prominent date selection
  variant: z.enum(["default", "subtle"]).optional(), // Visual variant. - `"default"` — Standard appearance with overlay background - `"subtle"` — Minimal background
  timezone: z.string().optional(), // Display timezone string shown in the footer.
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  onStartDateChange: z.unknown().optional(), // Callback when start date changes
  onEndDateChange: z.unknown().optional(), // Callback when end date changes
});

export const DialogPropsSchema = z.object({
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Dialog content (typically Title, Description, Close, and action buttons).
  size: z.enum(["base", "sm", "lg", "xl"]).optional(), // Dialog width. - `"sm"` — Small (min 288px) for simple confirmations - `"base"` — Default (min 384px) - `"lg"` — Large (min 512px) for complex content - `"xl"` — Extra large (min 768px) for detailed views
});

export const DropdownMenuPropsSchema = z.object({
  variant: z.enum(["default", "danger"]).optional(), // Visual style of the dropdown item. - `"default"` — Standard item appearance - `"danger"` — Destructive action with red text
});

export const EmptyPropsSchema = z.object({
  size: z.enum(["sm", "base", "lg"]).optional(), // Size of the empty state container. - `"sm"` — Compact empty state for smaller containers - `"base"` — Default empty state size - `"lg"` — Large empty state for prominent placement
  icon: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Decorative icon displayed above the title (e.g. from `@phosphor-icons/react`).
  title: z.string(), // Primary heading text for the empty state.
  description: z.string().optional(), // Secondary description text displayed below the title.
  commandLine: z.string().optional(), // Shell command displayed in a copyable code block.
  contents: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Additional content (buttons, links) rendered below the description.
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
});

export const FieldPropsSchema = z.object({
  controlFirst: z.boolean().optional(), // When `true`, places the control before the label (for checkbox/switch layouts).
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // The form control element(s) to wrap (Input, Select, Checkbox, etc.).
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // The label content — can be a string or any React node.
  required: z.boolean().optional(), // When explicitly `false`, shows gray "(optional)" text after the label. When `true` or `undefined`, no indicator is shown.
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content displayed next to the label via an info icon.
  error: z.unknown().optional(), // Validation error with a message and a browser `ValidityState` match key.
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Helper text displayed below the control (hidden when `error` is present).
});

export const GridPropsSchema = z.object({
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Grid items to render.
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  id: z.string().optional(),
  lang: z.string().optional(),
  title: z.string().optional(),
  mobileDivider: z.boolean().optional(), // Show dividers between grid items on mobile (only works with `"4up"` variant).
  gap: z.enum(["none", "sm", "base", "lg"]).optional(), // Gap size between grid items. - `"none"` — No gap - `"sm"` — 12px gap - `"base"` — Responsive gap (8px → 24px → 32px) - `"lg"` — 32px gap
  variant: z.enum(["2up", "side-by-side", "2-1", "1-2", "1-3up", "3up", "4up", "6up", "1-2-4up"]).optional(), // Responsive column layout variant. - `"2up"` — 1 col → 2 cols at md - `"side-by-side"` — Always 2 cols - `"2-1"` — 66%/33% split at md - `"1-2"` — 33%/66% split at md - `"3up"` — 1 → 2 → 3 cols - `"4up"` — 1 → 2 → 3 → 4 cols - `"6up"` — 2 → 3 → 4 → 6 cols - `"1-2-4up"` — 1 → 2 → 4 cols
});

export const InputPropsSchema = z.object({
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Label content for the input (enables Field wrapper) - can be a string or any React node
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content to display next to the label via an info icon
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Helper text displayed below the input
  error: z.unknown().optional(), // Error message or validation error object
  size: z.enum(["xs", "sm", "base", "lg"]).optional(), // Input size. - `"xs"` — Extra small for compact UIs - `"sm"` — Small for secondary fields - `"base"` — Default size - `"lg"` — Large for prominent fields
  variant: z.enum(["default", "error"]).optional(), // Visual variant. - `"default"` — Standard input - `"error"` — Error state for validation failures
});

export const InputAreaPropsSchema = z.object({});

export const LabelPropsSchema = z.object({
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // The label content — can be a string or any React node.
  showOptional: z.boolean().optional(), // When `true`, shows gray "(optional)" text after the label.
  tooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content displayed next to the label via an info icon.
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  htmlFor: z.string().optional(), // The id of the form element this label is associated with
  asContent: z.boolean().optional(), // When true, only renders the inline content (indicators, tooltip) without the outer label element with font styling. Useful when composed inside another label element that already provides the text styling.
});

export const LayerCardPropsSchema = z.object({
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
});

export const LinkPropsSchema = z.object({
  variant: z.enum(["inline", "current", "plain"]).optional(), // Visual style of the link. - `"inline"` — Inline text link that flows with content - `"current"` — Link that inherits color from parent text - `"plain"` — Link without underline decoration
  to: z.string().optional(),
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  className: z.string().optional(),
  id: z.string().optional(),
  lang: z.string().optional(),
  title: z.string().optional(),
  download: z.unknown().optional(),
  href: z.string().optional(),
  hrefLang: z.string().optional(),
  media: z.string().optional(),
  ping: z.string().optional(),
  target: z.unknown().optional(),
  type: z.string().optional(),
  referrerPolicy: z.enum(["", "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "same-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url"]).optional(),
  render: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
});

export const LoaderPropsSchema = z.object({
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  size: z.enum(["sm", "base", "lg"]).optional(), // Size of the spinner. Use a preset name or a custom pixel number. - `"sm"` — 16px, for inline use - `"base"` — 24px, default size - `"lg"` — 32px, for prominent loading states
});

export const MenuBarPropsSchema = z.object({
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  isActive: z.unknown().optional(), // The currently active option value — matched against option index or `id`.
  options: z.array(z.unknown()), // Array of menu option configurations.
  optionIds: z.boolean().optional(), // When true, each option's `id` field is used for matching instead of its array index.
});

export const MeterPropsSchema = z.object({
  customValue: z.string().optional(), // Custom formatted value text (e.g. "750 / 1,000") displayed instead of percentage.
  label: z.string(), // Label text displayed above the meter track.
  showValue: z.boolean().optional(), // Whether to display the percentage value next to the label.
  trackClassName: z.string().optional(), // Additional CSS classes for the track (background bar).
  indicatorClassName: z.string().optional(), // Additional CSS classes for the indicator (filled bar).
  value: z.number().optional(), // Current value of the meter
  max: z.number().optional(), // Maximum value of the meter (default: 100)
  min: z.number().optional(), // Minimum value of the meter (default: 0)
});

export const PaginationPropsSchema = z.object({
  setPage: z.unknown(), // Callback when page changes
  page: z.number().optional(), // Current page number (1-indexed).
  perPage: z.number().optional(), // Number of items displayed per page.
  totalCount: z.number().optional(), // Total number of items across all pages.
  className: z.string().optional(), // Additional CSS classes for the container
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Compound component children for custom layouts. Use Pagination.Info, Pagination.PageSize, Pagination.Controls, and Pagination.Separator.
  controls: z.enum(["full", "simple"]).optional(),
  text: z.unknown().optional(),
});

export const PopoverPropsSchema = z.object({
  side: z.enum(["top", "bottom", "left", "right"]).optional(), // Which side of the trigger the popover appears on. - `"top"` — Above the trigger - `"bottom"` — Below the trigger - `"left"` — Left of the trigger - `"right"` — Right of the trigger
});

export const RadioPropsSchema = z.object({
  legend: z.string(), // Legend text for the group (required for accessibility)
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Child Radio.Item components
  orientation: z.enum(["vertical", "horizontal"]).optional(), // Layout direction of the radio items
  appearance: z.enum(["default", "card"]).optional(), // Visual appearance applied to all Radio.Item children. - `"default"` — Standard inline radio items - `"card"` — Choice card with border, padding, and highlighted selection state Individual items can override this with their own `appearance` prop.
  error: z.string().optional(), // Error message for the group
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Helper text for the group
  value: z.string().optional(), // Value of the radio that should be selected (controlled)
  disabled: z.boolean().optional(), // Whether all radios in the group are disabled
  controlPosition: z.enum(["start", "end"]).optional(), // Position of radio control relative to label: "start" (default) puts radio before label, "end" puts label before radio. Note: In card appearance, the control is always positioned at the end.
  name: z.string().optional(), // Form submission name for the radio group
  className: z.string().optional(), // Additional CSS classes
});

export const SelectPropsSchema = z.object({
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Label content for the select. When provided, enables the Field wrapper with a visible label above the select. For accessibility without a visible label, use `aria-label` instead.
  hideLabel: z.boolean().optional(),
  placeholder: z.string().optional(), // Placeholder text shown when no value is selected.
  loading: z.boolean().optional(), // When `true`, shows a skeleton loader in place of the selected value.
  disabled: z.boolean().optional(), // Whether the select is disabled.
  required: z.boolean().optional(), // Whether the select is required. When `false`, shows "(optional)" text.
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content displayed next to the label via an info icon.
  value: z.string().optional(), // Currently selected value (controlled mode).
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // `Select.Option` elements to render in the dropdown.
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Helper text displayed below the select.
  error: z.unknown().optional(), // Error message string or validation error object with `match` key.
  onValueChange: z.unknown().optional(), // Callback when selection changes
  defaultValue: z.string().optional(), // Initial value for uncontrolled mode
});

export const SensitiveInputPropsSchema = z.object({
  alt: z.string().optional(),
  autoComplete: z.unknown().optional(),
  checked: z.boolean().optional(),
  disabled: z.boolean().optional(),
  height: z.unknown().optional(),
  list: z.string().optional(),
  name: z.string().optional(),
  placeholder: z.string().optional(),
  readOnly: z.boolean().optional(),
  required: z.boolean().optional(),
  width: z.unknown().optional(),
  className: z.string().optional(),
  id: z.string().optional(),
  lang: z.string().optional(),
  title: z.string().optional(),
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(),
  value: z.string().optional(), // Controlled value
  size: z.enum(["xs", "sm", "base", "lg"]).optional(), // Size of the input. - `"xs"` — Extra small for compact UIs - `"sm"` — Small for secondary fields - `"base"` — Default input size - `"lg"` — Large for prominent fields
  variant: z.enum(["default", "error"]).optional(), // Style variant of the input. - `"default"` — Default input appearance - `"error"` — Error state for validation failures
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Label content for the input (enables Field wrapper and sets masked state label) - can be a string or any React node
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content to display next to the label via an info icon
  description: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Helper text displayed below the input
  error: z.unknown().optional(), // Error message or validation error object
});

export const SurfacePropsSchema = z.object({
  as: z.unknown().optional(), // The HTML element type to render as (e.g. `"div"`, `"section"`, `"article"`).
  className: z.string().optional(), // Additional CSS classes merged via `cn()`.
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Content rendered inside the surface.
});

export const SwitchPropsSchema = z.object({
  variant: z.enum(["default", "neutral"]).optional(), // Visual variant: "default" (pill, brand color) or "neutral" (squircle, monochrome)
  label: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Label content for the switch (Field wrapper is built-in) - can be a string or any React node. Optional when used standalone for visual-only purposes.
  labelTooltip: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Tooltip content to display next to the label via an info icon
  required: z.boolean().optional(), // Whether the switch is required. When explicitly false, shows "(optional)" text after the label.
  controlFirst: z.boolean().optional(), // When true (default), switch appears before label. When false, label appears before switch.
  size: z.enum(["sm", "base", "lg"]).optional(),
  checked: z.boolean().optional(),
  disabled: z.boolean().optional(),
  transitioning: z.boolean().optional(),
  name: z.string().optional(),
  type: z.enum(["submit", "reset", "button"]).optional(),
  value: z.unknown().optional(),
  className: z.string().optional(),
  id: z.string().optional(),
  lang: z.string().optional(),
  title: z.string().optional(),
  onClick: z.unknown(), // Callback when switch is clicked
});

export const TablePropsSchema = z.object({
  layout: z.enum(["auto", "fixed"]).optional(),
  variant: z.enum(["default", "selected"]).optional(),
  className: z.string().optional(), // Additional CSS classes
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Child elements
});

export const TabsPropsSchema = z.object({
  tabs: z.array(z.unknown()).optional(), // Array of tab items to render.
  value: z.string().optional(), // Controlled value. When set, component becomes controlled.
  selectedValue: z.string().optional(), // Default selected value for uncontrolled mode. Ignored when `value` is set.
  activateOnFocus: z.boolean().optional(), // When `true`, tabs are activated immediately upon receiving focus via arrow keys. When `false` (default), tabs receive focus but require Enter/Space to activate.
  className: z.string().optional(), // Additional CSS classes for the root element.
  listClassName: z.string().optional(), // Additional CSS classes for the tab list element.
  indicatorClassName: z.string().optional(), // Additional CSS classes for the indicator element.
  variant: z.enum(["segmented", "underline"]).optional(), // Tab style. - `"segmented"` — Pill-shaped indicator on a filled track - `"underline"` — Underline indicator below tab text
  onValueChange: z.unknown().optional(), // Callback when active tab changes
});

export const TextPropsSchema = z.object({
  variant: z.enum(["heading1", "heading2", "heading3", "body", "secondary", "success", "error", "mono", "mono-secondary"]).optional(), // Text style variant. Determines color, font, and weight. - `"heading1"` — Large page title (30px, semibold) - `"heading2"` — Section title (24px, semibold) - `"heading3"` — Subsection title (18px, semibold) - `"body"` — Default body text - `"secondary"` — Muted text for secondary information - `"success"` — Success state text - `"error"` — Error state text - `"mono"` — Monospace text for code - `"mono-secondary"` — Muted monospace text
  size: z.enum(["xs", "sm", "base", "lg"]).optional(), // Text size (only applies to body/secondary/success/error variants). - `"xs"` — 12px - `"sm"` — 14px - `"base"` — 16px - `"lg"` — 18px
  bold: z.boolean().optional(), // Whether to use bold font weight (only applies to body variants).
  as: z.unknown().optional(), // The HTML element type to render as (e.g. `"span"`, `"p"`, `"h1"`). Auto-selected based on variant if omitted.
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Text content.
});

export const ToastyPropsSchema = z.object({
  variant: z.enum(["default", "error", "warning"]).optional(),
  className: z.string().optional(), // Additional CSS classes
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Child elements
});

export const TooltipPropsSchema = z.object({
  side: z.enum(["top", "bottom", "left", "right"]).optional(),
  className: z.string().optional(), // Additional CSS classes
  children: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]).optional(), // Child elements
  content: z.union([z.string(), z.number(), z.boolean(), z.null(), DynamicValueSchema]), // Content to display in the tooltip
});

// =============================================================================
// Component Type Union
// =============================================================================

/**
 * All valid component type names
 */
export type KumoComponentType = "Badge" | "Banner" | "Breadcrumbs" | "Button" | "Checkbox" | "ClipboardText" | "CloudflareLogo" | "Code" | "Collapsible" | "Combobox" | "CommandPalette" | "DatePicker" | "DateRangePicker" | "Dialog" | "DropdownMenu" | "Empty" | "Field" | "Grid" | "Input" | "InputArea" | "Label" | "LayerCard" | "Link" | "Loader" | "MenuBar" | "Meter" | "Pagination" | "Popover" | "Radio" | "Select" | "SensitiveInput" | "Surface" | "Switch" | "Table" | "Tabs" | "Text" | "Toasty" | "Tooltip";

export const KumoComponentTypeSchema = z.enum([
  "Badge",
  "Banner",
  "Breadcrumbs",
  "Button",
  "Checkbox",
  "ClipboardText",
  "CloudflareLogo",
  "Code",
  "Collapsible",
  "Combobox",
  "CommandPalette",
  "DatePicker",
  "DateRangePicker",
  "Dialog",
  "DropdownMenu",
  "Empty",
  "Field",
  "Grid",
  "Input",
  "InputArea",
  "Label",
  "LayerCard",
  "Link",
  "Loader",
  "MenuBar",
  "Meter",
  "Pagination",
  "Popover",
  "Radio",
  "Select",
  "SensitiveInput",
  "Surface",
  "Switch",
  "Table",
  "Tabs",
  "Text",
  "Toasty",
  "Tooltip",
]);

/**
 * Map of component type to its props schema
 */
export const ComponentPropsSchemas = {
  Badge: BadgePropsSchema,
  Banner: BannerPropsSchema,
  Breadcrumbs: BreadcrumbsPropsSchema,
  Button: ButtonPropsSchema,
  Checkbox: CheckboxPropsSchema,
  ClipboardText: ClipboardTextPropsSchema,
  CloudflareLogo: CloudflareLogoPropsSchema,
  Code: CodePropsSchema,
  Collapsible: CollapsiblePropsSchema,
  Combobox: ComboboxPropsSchema,
  CommandPalette: CommandPalettePropsSchema,
  DatePicker: DatePickerPropsSchema,
  DateRangePicker: DateRangePickerPropsSchema,
  Dialog: DialogPropsSchema,
  DropdownMenu: DropdownMenuPropsSchema,
  Empty: EmptyPropsSchema,
  Field: FieldPropsSchema,
  Grid: GridPropsSchema,
  Input: InputPropsSchema,
  InputArea: InputAreaPropsSchema,
  Label: LabelPropsSchema,
  LayerCard: LayerCardPropsSchema,
  Link: LinkPropsSchema,
  Loader: LoaderPropsSchema,
  MenuBar: MenuBarPropsSchema,
  Meter: MeterPropsSchema,
  Pagination: PaginationPropsSchema,
  Popover: PopoverPropsSchema,
  Radio: RadioPropsSchema,
  Select: SelectPropsSchema,
  SensitiveInput: SensitiveInputPropsSchema,
  Surface: SurfacePropsSchema,
  Switch: SwitchPropsSchema,
  Table: TablePropsSchema,
  Tabs: TabsPropsSchema,
  Text: TextPropsSchema,
  Toasty: ToastyPropsSchema,
  Tooltip: TooltipPropsSchema,
} as const;

// =============================================================================
// UI Element & Tree Schemas
// =============================================================================

/**
 * Base UI element structure
 */
export const UIElementBaseSchema = z.object({
  key: z.string(),
  type: KumoComponentTypeSchema,
  props: z.record(z.string(), z.unknown()),
  children: z.array(z.string()).optional(),
  parentKey: z.string().nullable().optional(),
  visible: VisibilityConditionSchema.optional(),
  action: ActionSchema.optional(),
});

export type UIElement = z.infer<typeof UIElementBaseSchema>;

/**
 * Flat UI tree structure (optimized for LLM generation)
 */
export const UITreeSchema = z.object({
  root: z.string(),
  elements: z.record(z.string(), UIElementBaseSchema),
});

export type UITree = z.infer<typeof UITreeSchema>;

// =============================================================================
// Validation Helpers
// =============================================================================

/**
 * Validate an element's props against its component schema
 */
export function validateElementProps(element: UIElement): SafeParseResult<unknown> {
  const schema = ComponentPropsSchemas[element.type as keyof typeof ComponentPropsSchemas];
  if (!schema) {
    return { success: false, error: new z.ZodError([{ code: 'custom', message: `Unknown component type: ${element.type}`, path: ['type'] }]) };
  }
  return schema.safeParse(element.props);
}

/**
 * Validate a complete UI tree
 */
export function validateUITree(tree: unknown): SafeParseResult<UITree> {
  return UITreeSchema.safeParse(tree);
}

/**
 * List of all component names (for catalog generation)
 */
export const KUMO_COMPONENT_NAMES = ["Badge", "Banner", "Breadcrumbs", "Button", "Checkbox", "ClipboardText", "CloudflareLogo", "Code", "Collapsible", "Combobox", "CommandPalette", "DatePicker", "DateRangePicker", "Dialog", "DropdownMenu", "Empty", "Field", "Grid", "Input", "InputArea", "Label", "LayerCard", "Link", "Loader", "MenuBar", "Meter", "Pagination", "Popover", "Radio", "Select", "SensitiveInput", "Surface", "Switch", "Table", "Tabs", "Text", "Toasty", "Tooltip"] as const;
