import { Popper, useAutocomplete, UseAutocompleteProps } from '@mui/base';
import clsx from 'clsx';
import React, { ChangeEvent } from 'react';
import { noop } from '../../../helpers/utils';
import { Button, ButtonContext } from '../../Buttons';
import { IconName } from '../../Icons';
import { BaseFormControl, BaseInputEvents } from '../Form.models';
import { FormElementContainer } from '../FormElementContainer';
import classes from './Select.scss';

export interface SelectOption {
  value: string | number | string[];
  label: string | number;
}

type TrimmedUseAutocompleteProps = Omit<
  UseAutocompleteProps<SelectOption, false, true, false>,
  'value' | 'onChange'
>;
export interface SelectProps
  extends BaseFormControl,
    BaseInputEvents,
    TrimmedUseAutocompleteProps {
  /** An array of options */
  options: SelectOption[];
  /** Whether or not the control should start focused (default: false) */
  autoFocus?: boolean;
  /** Current value the form control has */
  value?: string | string[] | number;
  /** Select placeholder */
  placeholder?: string;
  /** Allows to clear the input field and leave empty  */
  addEmptyOption?: boolean;
}

export const Select: React.FC<SelectProps> = (props) => {
  const {
    name,
    error,
    disabled,
    id,
    label,
    className,
    tooltipContent,
    inlineMode,
    autoFocus,
    value,
    onBlur,
    onFocus,
    onChange,
    placeholder,
    addEmptyOption,
    ...autoCompleteProps
  } = props;
  const {
    getRootProps,
    getInputProps,
    getListboxProps,
    getOptionProps,
    getPopupIndicatorProps,
    groupedOptions,
    popupOpen,
    setAnchorEl,
    anchorEl,
  } = useAutocomplete({
    id,
    disabled,
    value:
      autoCompleteProps.options?.find((option) => option.value === value) ??
      null,
    onChange: ({ target: _, ...event }, value) => {
      onChange?.({
        ...event,
        currentTarget: {
          ...event.currentTarget,
          id,
          name,
          value: value?.value ?? '',
        },
        preventDefault: noop,
      } as ChangeEvent<HTMLInputElement>);
    },
    disableClearable: !addEmptyOption,
    ...autoCompleteProps,
  });

  return (
    <FormElementContainer
      label={label}
      tooltipContent={tooltipContent}
      inlineMode={inlineMode}
      className={clsx(classes.container, 'select-container', className)}
      error={error}
      dataTestFieldType="Select"
      htmlFor={id ?? name}
    >
      <div
        ref={setAnchorEl}
        {...getRootProps()}
        className={clsx(classes.inputWrapper)}
      >
        <input
          {...getInputProps()}
          id={id ?? name}
          name={name}
          className={clsx({ [classes.hasError]: Boolean(error) })}
          autoFocus={autoFocus}
          onBlur={(event) => {
            getInputProps().onBlur?.(event);
            onBlur?.(event);
          }}
          onFocus={(event) => {
            getInputProps().onFocus?.(event);
            onFocus?.(event);
          }}
          placeholder={placeholder}
        />
        <Button
          className={clsx(classes.button)}
          buttonContext={ButtonContext.None}
          icon={popupOpen ? IconName.ChevronUp : IconName.ChevronDown}
          onButtonClicked={getPopupIndicatorProps().onClick}
          onBlur={getPopupIndicatorProps().onBlur}
          disabled={disabled}
        />
      </div>
      <Popper
        open={popupOpen}
        anchorEl={anchorEl}
        style={{
          width: anchorEl ? anchorEl.clientWidth : undefined,
          zIndex: 999,
        }}
      >
        <PopperContent>
          {groupedOptions.length > 0 && (
            <ul {...getListboxProps()}>
              {(groupedOptions as typeof autoCompleteProps.options).map(
                (option, index) => (
                  <li
                    key={String(option.value)}
                    {...getOptionProps({ option, index })}
                  >
                    {option.label}
                  </li>
                ),
              )}
            </ul>
          )}
        </PopperContent>
      </Popper>
    </FormElementContainer>
  );
};

const PopperContent: React.FC = ({ children }) => {
  return (
    <div className={clsx(classes.popperContent, 'select-popper-content')}>
      {children}
    </div>
  );
};
