/**
 * `<select-ui>` — Custom-styled select / combobox / multi-select.
 *
 * @see https://ui-kit.exe.xyz/site/components/select
 */

import { UIFormElement } from '../../core/form.js';

export interface SelectOption {
  value: string;
  label?: string;
  icon?: string;
  avatar?: string;
  disabled?: boolean;
  action?: string;
  divider?: boolean;
}

export interface SelectChangeEventDetail<V extends string = string> {
  /** Single-select: the new value. Multi-select: array of selected ids. */
  value: V | V[];
  /** Multi-select only: ids added in this change. */
  added?: V[];
  /** Multi-select only: ids removed in this change. */
  removed?: V[];
}
export type SelectChangeEvent<V extends string = string> = CustomEvent<SelectChangeEventDetail<V>>;

export interface SelectActionEventDetail {
  action: string;
}
export type SelectActionEvent = CustomEvent<SelectActionEventDetail>;

/** SPEC-040 — fired when [multiple] toggle suppressed by min/max constraints. */
export interface SelectInvalidEventDetail {
  value: string[];
  reason: 'min' | 'max';
}
export type SelectInvalidEvent = CustomEvent<SelectInvalidEventDetail>;

export class UISelect extends UIFormElement {
  placeholder: string;
  /** Open/closed reflected attribute — toggled by trigger click / keyboard. */
  open: boolean;
  label: string;
  /** Leading icon name (Phosphor registry). */
  icon: string;
  /** Leading avatar URL or name. */
  avatar: string;
  multiple: boolean;
  searchable: boolean;
  /** Allow values not in the option list (combobox mode). */
  freeText: boolean;
  divider: boolean;
  /** SPEC-040 — cap visible chips in multi-select trigger. 0 = unlimited. */
  maxChips: number;
  /** SPEC-040 — minimum required selections in multi-select mode. */
  min: number;
  /** SPEC-040 — maximum allowed selections in multi-select mode. 0 = unlimited. */
  max: number;
  /** SPEC-040 — render Select-all / Clear control above the option list. */
  selectAll: boolean;
  /** SPEC-040 — render a clear-all `x` affordance in the trigger. */
  clearable: boolean;
  /** §207 (v0.5.7): hint text below the field, wired to aria-describedby. */
  hint: string;
  /**
   * §247 (v0.5.10, FB-26 §1): visual variant. `default` = canonical chrome
   * (border + bg); `outline` = bordered transparent; `ghost` = inline
   * (no border); `soft` = subtle background tint. Mirrors `<input-ui>`
   * variant family.
   */
  variant: 'default' | 'outline' | 'ghost' | 'soft';
  /**
   * §247 (v0.5.10, FB-26 §1): universal `[size]` attribute system —
   * `xs` / `sm` / `md` (default) / `lg` / `xl`. Sets `--a-size` token
   * locally; cascades to child icons / labels via the size-cascade pattern
   * documented in USAGE.md §221a.
   */
  size: 'xs' | 'sm' | 'md' | 'lg' | 'xl';

  /**
   * Dynamic option list. Setting `.options = [...]` stamps option elements at
   * connection time + auto-syncs the listbox.
   */
  options: readonly SelectOption[];

  /** SPEC-040 — toggle one option's selection in multi-select mode. */
  toggle(id: string): void;
  /** SPEC-040 — select every non-disabled option in multi-select mode. */
  selectAllOptions(): void;
  /** SPEC-040 — clear all selections. */
  clear(): void;

  addEventListener<K extends keyof HTMLElementEventMap>(
    type: K,
    listener: (this: UISelect, ev: HTMLElementEventMap[K]) => unknown,
    options?: boolean | AddEventListenerOptions,
  ): void;
  addEventListener(type: 'change', listener: (ev: SelectChangeEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
  addEventListener(type: 'action', listener: (ev: SelectActionEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
  addEventListener(type: 'invalid', listener: (ev: SelectInvalidEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
}
