import * as Ariakit from '@ariakit/react';
import { IOption } from '@websolutespa/bom-core';
import { FocusEvent, useEffect, useState } from 'react';
import { useVariants } from '../../variants';
import { innerToOuterValue, outerToInnerSingleValue, outerToInnerValue } from '../utils/utils';
import { ComboboxContext } from './combobox.context';
import { comboboxVariants, IComboboxVariants } from './combobox.variants';

type Props = {
  name?: string;
  label?: string;
  value?: string | IOption | null;
  defaultValue?: string | null;
  selectedValue?: string | IOption | string[] | IOption[] | null;
  defaultSelectedValue?: string | IOption | string[] | IOption[] | null;
  options?: IOption[];
  multiple?: boolean;
  variant?: keyof typeof comboboxVariants | (string & {});
  variants?: IComboboxVariants;
  onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
  onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
  onChange?: (value: string | IOption | string[] | IOption[] | null) => void;
};

export type ComboboxProps = Omit<Ariakit.ComboboxProviderProps, keyof Props> & Props;

export function Combobox({
  name,
  label: outerLabel,
  value: outerValue,
  defaultValue: outerDefaultValue,
  selectedValue: outerSelectedValue,
  defaultSelectedValue: outerDefaultSelectedValue,
  options,
  multiple,
  variant = 'default',
  variants,
  onBlur,
  onFocus,
  onChange,
  children,
  ...props }: ComboboxProps) {

  const value = outerToInnerSingleValue(outerValue);
  const defaultValue = outerToInnerSingleValue(outerDefaultValue) || '';
  const [innerValue, setInnerValue] = useState<string | undefined>(value || defaultValue);
  const selectedValue = outerToInnerValue(outerSelectedValue);
  const defaultSelectedValue = outerToInnerValue(outerDefaultSelectedValue) || (multiple ? [] : '');
  const [innerSelectedValue, setInnerSelectedValue] = useState<string | string[] | undefined>();

  // console.log('value', value, 'defaultValue', defaultValue);

  useEffect(() => {
    const value = outerToInnerSingleValue(outerValue);
    if (innerValue !== value) {
      setInnerValue(value);
    }
  }, [innerValue, outerValue]);

  useEffect(() => {
    const selectedValue = outerToInnerValue(outerSelectedValue);
    if (innerSelectedValue !== selectedValue) {
      // const value = Array.isArray(selectedValue) ? selectedValue[0] : selectedValue;
      // setInnerValue(value);
      setInnerSelectedValue(selectedValue);
      if (selectedValue) {
        setInnerValue(Array.isArray(selectedValue) ? selectedValue[0] : selectedValue);
      } else {
        setInnerValue('');
      }
      // console.log('Combobox', innerSelectedValue, selectedValue);
    }
  }, [innerSelectedValue, outerSelectedValue]);

  const onBlur_ = (event: FocusEvent<HTMLInputElement>) => {
    /*
    if (selectedValue) {
      setInnerValue(Array.isArray(selectedValue) ? selectedValue[0] : selectedValue);
    }
    */
    onBlur && onBlur(event);
  };

  const onFocus_ = (event: FocusEvent<HTMLInputElement>) => {
    // console.log('onFocus_', selectedValue);
    /*
    if (selectedValue) {
      setInnerValue('');
    }
    */
    onFocus && onFocus(event);
  };

  const onSetValue = (value: string) => {
    if (innerValue !== value) {
      setInnerValue(value);
    }
  };

  const onSetSelectedValue = (value: string | string[]) => {
    if (innerSelectedValue !== value) {
      setInnerSelectedValue(value);
      const outerSelectedValue = innerToOuterValue(value, options);
      onChange && onChange(outerSelectedValue);
    }
  };

  const globalVariants = useVariants('combobox', comboboxVariants);
  variants = variants || globalVariants;
  return (
    <Ariakit.ComboboxProvider
      defaultValue={defaultValue}
      value={innerValue}
      setValue={onSetValue}
      defaultSelectedValue={defaultSelectedValue}
      selectedValue={innerSelectedValue}
      setSelectedValue={onSetSelectedValue}
      {...props}
    >
      <ComboboxContext.Provider value={{
        name,
        label: outerLabel,
        value: outerValue,
        defaultValue: outerDefaultValue,
        options,
        multiple,
        variant,
        variants,
        onFocus: onFocus_,
        onBlur: onBlur_,
      }}>
        {children}
      </ComboboxContext.Provider>
    </Ariakit.ComboboxProvider>
  );
}
