import type { Conditional, ConditionParam } from "./conditions"
import type { ResponsiveColumns } from "./responsive"

/**
 * Union of every CardElement category — the prefix half of an
 * element's dot-notation `type` discriminator. Each value here
 * corresponds to one file under `definitions/elements/` and one folder
 * under `elements/`.
 */
export type ElementCategory =
  | "action"
  | "boolean"
  | "builder"
  | "card"
  | "code"
  | "configuration-block"
  | "display"
  | "editor"
  | "file"
  | "input"
  | "option-select"
  | "picker"

/**
 * Dot-notation discriminator: `"<category>.<style>"`. Combines what
 * previously lived in two fields (`type` + `style`) into a single
 * string so it doesn't collide with Vue's HTML `style` attribute
 * fallthrough behaviour.
 *
 * Each per-category interface narrows this to its own valid styles —
 * e.g. `InputElement["type"]` is `\`input.${InputStyle}\``.
 */
export type ElementType = `${ElementCategory}.${string}`

/**
 * Properties common to every CardElement (input, picker, display, etc.).
 *
 * `type` is a `"category.style"` string. The engine's registry resolves
 * it directly to a Vue renderer path. `name` is the form-data key for
 * input-bearing elements.
 */
export interface BaseElement<TType extends ElementType = ElementType>
  extends Conditional,
    ResponsiveColumns {
  /** Stable identifier. Required by the engine; FormBuilder generates UUIDs. */
  id: string
  type: TType
  /** Form-data key. Required for input-bearing elements. */
  name?: string | null
  label?: string
  /** Hide the label while keeping the element labelled for screen readers. */
  hideLabel?: boolean
  defaultValue?: unknown
  required?: boolean
  readonly?: boolean
  disabled?: boolean
  placeholder?: string
  helpText?: string
  tooltip?: string
  tooltipOptions?: {
    maxWidth?: string
    direction?: "top" | "right" | "bottom" | "left"
  }
  /** Extra classes applied to the element's root. */
  classList?: string[] | string
  /** Classes on the wrapper around the element + label. */
  wrapperClassList?: string[] | string
  /** Classes on the column wrapper. */
  columnClassList?: string[] | string
  /** Classes on the label element. */
  labelClassList?: string[] | string
  /** If true, the element renders in display-only preview mode. */
  previewMode?: boolean
  /** Ordering used by builders. */
  order?: number
}

/**
 * Union of every DisplayCard type. Mirrors the existing v2 schema.
 */
export type CardType =
  | "card-list"
  | "tab-list"
  | "info-card"
  | "grid-view"
  | "element-list"
  | "element-display"
  | "datatable"

/**
 * Properties common to every DisplayCard (fields_list, data_table, etc.).
 *
 * Cards form the layout tree — they contain elements and/or other cards
 * via `cardList` / `tabList` / `elementList` depending on `cardType`.
 */
export interface BaseCard<TType extends string = CardType>
  extends Conditional,
    ResponsiveColumns {
  id: string
  /** Discriminator used by the engine to pick a renderer. */
  cardType: TType
  title?: string
  subtitle?: string
  /** Show the surrounding chrome (border, padding). */
  showCard?: boolean
  /** Wrap the card body in a Collapse with a heading. */
  collapse?: {
    heading?: string
    showingByDefault?: boolean
  }
  /** Optional footer button. */
  footerButton?: {
    text: string
    route?: string
    icon?: string
  }
  classList?: string[] | string
  wrapperClassList?: string[] | string
  order?: number
}

/**
 * Metadata used by builders / pickers to surface this element category
 * in lists and palettes. `elementCategory` matches the prefix half of
 * an element's dot-notation `type`.
 */
export interface ElementMetadata {
  icon: string
  displayLabel: string
  elementCategory: ElementCategory
  description: string
}

/**
 * A single field in an EditConfig — describes how the FormBuilder
 * inspector should render the corresponding property. It is structurally
 * identical to a CardElement (recursive), but typed loosely here to
 * avoid a circular reference. Stronger typing lives on the concrete
 * inspector field shapes inside each category's file.
 */
export interface EditConfigField {
  type: ElementType | string
  style?: string
  label?: string
  defaultValue?: unknown
  columns?: number
  columnsMd?: number
  columnsLg?: number
  section?: "configuration" | "layout" | "advanced" | "conditions" | string
  selectOptions?: ReadonlyArray<unknown>
  conditionParams?: ConditionParam[]
  // Per-type extras are permitted; renderers narrow further.
  [key: string]: unknown
}

export type EditConfig = Record<string, EditConfigField>

/**
 * Split a dot-notation `type` back into `{ category, style }`. Useful
 * for inspectors / debug badges that want to display the style suffix
 * without re-parsing inline.
 */
export function splitElementType(type: string): {
  category: ElementCategory | string
  style: string
} {
  const dot = type.indexOf(".")
  if (dot < 0) {
    return { category: type, style: "" }
  }
  return {
    category: type.slice(0, dot) as ElementCategory,
    style: type.slice(dot + 1),
  }
}

/** Build a `BaseElement["type"]` from a `(category, style)` pair. */
export function joinElementType(
  category: ElementCategory | string,
  style: string,
): ElementType {
  return `${category}.${style}` as ElementType
}
