import * as React from 'react';

import { default as SearchCategory, SearchCategoryProps } from './SearchCategory';
import { default as SearchResult, SearchResultProps } from './SearchResult';
import { default as SearchResults } from './SearchResults';

export interface SearchProps {
  [key: string]: any;

  /** An element type to render as (string or function). */
  as?: any;

  // ------------------------------------
  // Behavior
  // ------------------------------------

  /** Initial value of open. */
  defaultOpen?: boolean;

  /** Initial value. */
  defaultValue?: string;

  /** Shorthand for Icon. */
  icon?: any;

  /** Minimum characters to query for results. */
  minCharacters?: number;

  /** Additional text for "No Results" message with less emphasis. */
  noResultsDescription?: string;

  /** Message to display when there are no results. */
  noResultsMessage?: string;

  /** Controls whether or not the results menu is displayed. */
  open?: boolean;

  /**
   * One of:
   * - array of Search.Result props e.g. `{ title: '', description: '' }` or
   * - object of categories e.g. `{ name: '', results: [{ title: '', description: '' }]`
   */
  results?: Array<any> | Object;

  /** Whether the search should automatically select the first result after searching. */
  selectFirstResult?: boolean;

  /** Whether a "no results" message should be shown if no results are found. */
  showNoResults?: boolean;

  /** Current value of the search input. Creates a controlled component. */
  value?: string;

  // ------------------------------------
  // Rendering
  // ------------------------------------

  /**
   * Renders the SearchCategory contents.
   *
   * @param {object} props - The SearchCategory props object.
   * @returns {*} - Renderable SearchCategory contents.
   */
  categoryRenderer?: (props: SearchCategoryProps) => React.ReactElement<any>;

  /**
   * Renders the SearchResult contents.
   *
   * @param {object} props - The SearchResult props object.
   * @returns {*} - Renderable SearchResult contents.
   */
  resultRenderer?: (props: SearchResultProps) => Array<React.ReactElement<any>>;

  // ------------------------------------
  // Callbacks
  // ------------------------------------

  /**
   * Called on blur.
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - All props.
   */
  onBlur?: (event: React.MouseEvent<HTMLElement>, data: SearchProps) => void;

  /**
   * Called on focus.
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - All props.
   */
  onFocus?: (event: React.MouseEvent<HTMLElement>, data: SearchProps) => void;

  /**
   * Called on mousedown.
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - All props.
   */
  onMouseDown?: (event: React.MouseEvent<HTMLElement>, data: SearchProps) => void;

  /**
   * Called when a result is selected.
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - All props.
   */
  onResultSelect?: (event: React.MouseEvent<HTMLDivElement>, data: SearchResultProps) => void;

  /**
   * Called on search input change.
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {string} value - Current value of search input.
   */
  onSearchChange?: (event: React.MouseEvent<HTMLElement>, value: string) => void;

  // ------------------------------------
  // Style
  // ------------------------------------

  /** A search can have its results aligned to its left or right container edge. */
  aligned?: string;

  /** A search can display results from remote content ordered by categories. */
  category?: boolean;

  /** Additional classes. */
  className?: string;

  /** A search can have its results take up the width of its container. */
  fluid?: boolean;

  /** A search input can take up the width of its container. */
  input?: any;

  /** A search can show a loading indicator. */
  loading?: boolean;

  /** A search can have different sizes. */
  size?: 'mini' | 'tiny' | 'small' | 'large' | 'big' | 'huge' | 'massive';
}

interface SearchComponent extends React.ComponentClass<SearchProps> {
  Category: typeof SearchCategory;
  Result: typeof SearchResult;
  Results: typeof SearchResults;
}

declare const Search: SearchComponent;

export default Search;
