import type {
  BaseElement,
  EditConfig,
  ElementMetadata,
} from "@/definitions/shared/base"
import type { RouteRef } from "@/definitions/shared/route"
import type { SelectOptionLike } from "@/definitions/shared/select-options"
import type { ValidationConfig } from "@/definitions/shared/validation"

/**
 * Variants of the `option-select` element type. Each value here maps 1:1
 * to a Vue file under `src/elements/option-select/` via the engine's
 * registry.
 */
export type OptionSelectStyle =
  | "select"
  | "select-multiple"
  | "checkbox"
  | "radio"
  | "autocomplete"
  | "list"
  | "pill-select"

/**
 * Shape of the value held by an option-select element.
 * Multi-select variants emit an array; single-select variants emit a scalar.
 */
export type OptionSelectValue = string | number | Array<string | number> | null

export interface OptionSelectElement
  extends BaseElement<`option-select.${OptionSelectStyle}`> {
  name: string
  label?: string
  defaultValue?: OptionSelectValue
  required?: boolean
  readonly?: boolean
  /** Static option list. */
  selectOptions?: ReadonlyArray<SelectOptionLike>
  /** Reject values not present in `selectOptions`. */
  restrictOptions?: boolean
  /** Allow the user to clear the current selection. */
  clearable?: boolean
  /** For `radio` / `checkbox`: render options on the same row. */
  inline?: boolean
  /** For `select`-style: searchable dropdown. */
  searchable?: boolean
  /** For `autocomplete`: remote search endpoint. */
  searchRoute?: RouteRef
  /** For `autocomplete`: minimum chars before searching. */
  minSearchLength?: number
  /** Validation rules (Laravel-style strings). */
  validation?: ValidationConfig
}

export const OptionSelectElementDefaults = {
  type: "option-select.select",
  label: "Option Select Label",
  defaultValue: null,
  selectOptions: [],
  columns: 12,
  columnsSm: 12,
  columnsMd: 12,
  columnsLg: 12,
  columnsXl: 12,
} as const satisfies Partial<OptionSelectElement>

export const OptionSelectElementMetadata = {
  icon: "list-check",
  displayLabel: "Select From Options",
  elementCategory: "option-select",
  description:
    "Create an option-select field to allow users to select one or more options from a list. Can be displayed as a dropdown, checkboxes, radios, autocomplete, pill picker, and more.",
} as const satisfies ElementMetadata

/**
 * EditConfig describes how the FormBuilder inspector renders each
 * configurable property. Each key matches a property on
 * `OptionSelectElement`; the value is a (loosely-typed) element spec.
 */
export const OptionSelectElementEditConfig = {
  label: {
    type: "input.text",
    defaultValue: "",
    label: "Label",
    columns: 12,
    columnsMd: 6,
    section: "configuration",
  },
  name: {
    type: "picker.data-model",
    defaultValue: "",
    label: "Name",
    columns: 12,
    section: "advanced",
  },
  style: {
    type: "option-select.select",
    defaultValue: "select",
    label: "Select Style",
    columns: 12,
    selectOptions: [
      { label: "Select", value: "select" },
      { label: "Select (Multiple)", value: "select-multiple" },
      { label: "Checkbox", value: "checkbox" },
      { label: "Radio", value: "radio" },
      { label: "Autocomplete", value: "autocomplete" },
      { label: "List", value: "list" },
      { label: "Pill Select", value: "pill-select" },
    ],
    section: "layout",
  },
  defaultValue: {
    type: "input.text",
    label: "Default Value",
    columns: 12,
    columnsMd: 6,
    section: "configuration",
  },
  selectOptions: {
    type: "configuration-block.repeatable",
    label: "Options",
    columns: 12,
    section: "configuration",
    conditionParams: [
      {
        name: "style",
        logic: "in-array",
        value: [
          "select",
          "select-multiple",
          "checkbox",
          "radio",
          "list",
          "pill-select",
        ],
      },
    ],
  },
  restrictOptions: {
    type: "boolean.switch",
    label: "Restrict to Listed Options",
    columns: 6,
    section: "configuration",
    conditionParams: [
      {
        name: "style",
        logic: "in-array",
        value: ["select", "select-multiple", "autocomplete"],
      },
    ],
  },
  clearable: {
    type: "boolean.switch",
    label: "Allow Clear",
    columns: 6,
    section: "configuration",
    conditionParams: [
      {
        name: "style",
        logic: "in-array",
        value: ["select", "select-multiple", "autocomplete"],
      },
    ],
  },
  inline: {
    type: "boolean.switch",
    label: "Inline Options",
    columns: 6,
    section: "layout",
    conditionParams: [
      { name: "style", logic: "in-array", value: ["checkbox", "radio"] },
    ],
  },
  searchable: {
    type: "boolean.switch",
    label: "Searchable",
    columns: 6,
    section: "layout",
    conditionParams: [
      { name: "style", logic: "in-array", value: ["select", "select-multiple"] },
    ],
  },
  searchRoute: {
    type: "input.text",
    label: "Search Route",
    columns: 12,
    section: "configuration",
    conditionParams: [
      {
        name: "style",
        logic: "in-array",
        value: ["autocomplete"],
      },
    ],
  },
  minSearchLength: {
    type: "input.text",
    contentType: "integer",
    defaultValue: 1,
    label: "Min Search Length",
    columns: 6,
    section: "configuration",
    conditionParams: [
      {
        name: "style",
        logic: "in-array",
        value: ["autocomplete"],
      },
    ],
  },
  required: {
    type: "boolean.switch",
    label: "Make item required",
    columns: 6,
    section: "configuration",
  },
  readonly: {
    type: "boolean.switch",
    label: "Make item read-only",
    columns: 6,
    section: "configuration",
  },
} as const satisfies EditConfig

export const OptionSelectStyleMetadataMap: Partial<Record<OptionSelectStyle, { displayLabel: string; description: string }>> = {
  select: { displayLabel: "Select", description: "A single-value dropdown select." },
  "select-multiple": { displayLabel: "Multi Select", description: "A dropdown that allows selecting multiple values." },
  checkbox: { displayLabel: "Checkboxes", description: "A list of checkboxes for multi-value selection." },
  radio: { displayLabel: "Radio Buttons", description: "Radio buttons for selecting exactly one option." },
  autocomplete: { displayLabel: "Autocomplete", description: "A text input with live option suggestions." },
  list: { displayLabel: "List", description: "A scrollable list of selectable options." },
  "pill-select": { displayLabel: "Pill Select", description: "Selected values shown as removable pill tags." },
}
