import React, { useState, useEffect, useCallback } from 'react';

// Redux part
import { useSelector, useDispatch } from 'react-redux';
import { StoreState } from 'store/rootReducer';

// Import actions here

import classNames from 'classnames/bind';
import TextItem from 'components/items/TextItem';
import Suggestions from 'components/structure/Suggestions';
import { useDebouncedEffect } from 'components/hooks/debounce';
import { getTextFromObject, getValueFromObject } from 'store/utils/helper';
import Input from 'components/formItems/Input';
import styleIdentifiers from './SearchInput.module.scss';

const styles = classNames.bind(styleIdentifiers);

export interface SearchInputProps {}

const SearchInput = (props: SearchInputProps) => {
  const {
    className,
    searchLabel = 'search',
    noResultLabel = 'general.messages.noResult',
    noResult,
    inputClassName,
    input,
    modelValues,
    inputs,
    onSelect,
    loadData,
    itemRendering,
    resetItemsInput,
    treatmentData,
  } = props;
  // mapStateToProps
  const lg = useSelector((state: StoreState) => state.content.lg);
  // Allow to dispatch actions
  const dispatch = useDispatch();

  const [items, setItems] = useState([]);
  const [loaded, setLoaded] = useState(false);
  const [focused, setFocused] = useState(false);

  const selectValue = useCallback(
    item => {
      input.onChange(item?.text || '');
      let handler;
      // action to select
      if (onSelect) {
        handler = setTimeout(() => {
          onSelect(item);
        });
      }
      return () => {
        if (handler) clearTimeout(handler);
      };
    },
    [input],
  );

  const handleItems = res => {
    if (!res) return;

    if (treatmentData) {
      res = treatmentData(res);
    }

    for (let i = 0; i < res.length; i += 1) {
      const item = res[i];

      item.text = getTextFromObject(item, modelValues);
      item.value = getValueFromObject(item, modelValues);
    }

    setItems(res);
  };

  useEffect(() => {
    if (input?.value) return;

    selectValue(null);
  }, [input?.value]);

  // Watch inputs for a change in one specific field that should reset input value & items
  useEffect(() => {
    if (resetItemsInput && (!inputs || !inputs?.[resetItemsInput])) return;

    input.onChange('');
    setItems([]);
  }, [inputs?.[resetItemsInput]]);

  useEffect(() => {
    setLoaded(false);
  }, [input?.value]);

  useDebouncedEffect(async () => {
    if (!input?.value) return;

    const res = await loadData({
      noLoading: true,
      noToken: true,
      data: {
        ...inputs,
        [searchLabel]: input.value,
      },
      callbackError: () => {
        setLoaded(false);
      },
    });
    setLoaded(true);
    handleItems(res);
  }, [input?.value]);

  return (
    <Suggestions
      {...props}
      className={styles('search-input', className)}
      closeOnSelect
      externalActive={input.value?.length && (items?.length || loaded) && focused}
      selectValue={selectValue}
      items={items}
      noCheck
      debug
      loaded={loaded}
      itemRendering={itemRendering}
      noStyle={!!itemRendering}
      noResult={
        noResult || (
          <div className={styles('no-result')}>
            <TextItem path={noResultLabel} />
          </div>
        )
      }
    >
      <Input {...props} onFocus={() => setFocused(true)} onBlur={() => setFocused(false)} className={inputClassName} />
    </Suggestions>
  );
};

export default SearchInput;
