import { SvelteComponentTyped } from "svelte";
import type { SvelteHTMLElements } from "svelte/elements";

export type HeaderSearchResult = {
  /** Unique result identifier; used as the each-block key when provided */
  id?: string | number;
  href: string;
  text: string;
  description?: string;
};

export type CarbonSearchMenuContext = {
  query: any;
  shouldFilter: any;
  match: any;
  activeId: any;
  setActiveId: (next: any) => any;
  selectItem: (detail: any) => any;
  hasPrimaryItems: any;
  registerItem: (itemId: any, filterable: any, arg: any) => any;
  unregisterItem: (itemId: any) => any;
};

type $RestProps = SvelteHTMLElements["input"];

type $Props<Result extends HeaderSearchResult = HeaderSearchResult, Icon = any> = {
  /**
   * Specify the search input value.
   * @default ""
   */
  value?: string;

  /**
   * Set to `true` to activate and focus the search bar.
   * @default false
   */
  active?: boolean;

  /**
   * Obtain a reference to the input HTML element.
   * @default null
   */
  ref?: null | HTMLInputElement;

  /**
   * Render a list of search results.
   * @default []
   */
  results?: ReadonlyArray<Result>;

  /**
   * Specify the selected result index.
   * @default 0
   */
  selectedResultIndex?: number;

  /**
   * Specify the icon to render for the search trigger.
   * @default IconSearch
   */
  icon?: Icon;

  /**
   * Specify the `placeholder` attribute of the search input.
   * @default "Search..."
   */
  placeholder?: string;

  /**
   * Specify the text for the assistive label associated with the search input.
   * @default "Search"
   */
  labelText?: string;

  /**
   * Specify the label for the clear button.
   * @default "Clear search input"
   */
  closeButtonLabelText?: string;

  /**
   * Set to `true` to filter `menu`-slot items by the search value using fuzzy
   * matching. Requires the `menu` slot; ignored when using the `results` prop.
   * @default true
   */
  shouldFilter?: boolean;

  /**
   * Override how the search value is matched against each `menu`-slot item's
   * `text`. Receives the item `text` and the current search value, and returns
   * whether the item `matched` along with the `indices` of characters to
   * highlight. Defaults to fuzzy matching. Requires the `menu` slot.
   * @default fuzzyMatch
   */
  match?: (text: string, query: string) => {
    matched: boolean;
    indices?: number[]
  };

  /**
   * Set to `true` to render a skeleton menu while results are loading.
   * Override the placeholder rows with the `loading` slot. Requires the
   * `menu` slot.
   * @default false
   */
  loading?: boolean;

  /**
   * Number of skeleton rows while `loading`. Requires the `menu` slot.
   * @default 4
   */
  skeletonCount?: number;

  /**
   * Row density for the `menu` slot. Result text stays flush with the header
   * input; smaller sizes shorten rows to fit more results.
   * @default "sm"
   */
  size?: "sm" | "lg" | "xl";

  menu?: (this: void) => void;

  noResults?: (this: void) => void;

  children?: (this: void, ...args: [{
        result: Result;
        index: number;
        selected: boolean;
      }]) => void;

  [key: `data-${string}`]: unknown;
};

export type HeaderSearchProps<Result extends HeaderSearchResult = HeaderSearchResult, Icon = any> = Omit<$RestProps, keyof $Props<Result, Icon>> & $Props<Result, Icon>;

export default class HeaderSearch<Result extends HeaderSearchResult = HeaderSearchResult, Icon = any> extends SvelteComponentTyped<
  HeaderSearchProps<Result, Icon>,
  {
    active: CustomEvent<null>;
    blur: WindowEventMap["blur"];
    change: WindowEventMap["change"];
    clear: CustomEvent<null>;
    close: CustomEvent<{
        trigger: "escape-key" | "outside-click" | "select";
      }>;
    focus: WindowEventMap["focus"];
    inactive: CustomEvent<null>;
    input: WindowEventMap["input"];
    keydown: WindowEventMap["keydown"];
    paste: WindowEventMap["paste"];
    select: CustomEvent<{
        value: string;
        selectedResultIndex: number;
        selectedResult: Result;
      }>;
    submit: CustomEvent<{ value: string }>;
  },
  {
    default: {
      result: Result;
      index: number;
      selected: boolean;
    };
    loading: Record<string, never>;
    menu: Record<string, never>;
    noResults: Record<string, never>;
  }
> {}
