import React, { useEffect, useImperativeHandle, useRef, useState } from 'react';
import { useDidUpdateEffect, useEventListener } from '@devesharp/react-hooks';
import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import * as _ from 'lodash';
import { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect';
import { useImmer } from 'use-immer';
import {
   AutocompletePure,
   IComponentAutoCompleteAs,
   IPropsAutoComplete,
   IRefAutoCompleteAs,
} from '../AutocompletePure';
import { CloseBtn } from '../CloseBtn';
import { Input } from '../Input';
import { UnformInput } from '../UnformInput';
import { IInputTagsProps, IInputTagsTag } from './InputTags.interface';
import * as S from './InputTags.style';

const InputAutoComplete = React.forwardRef<IRefAutoCompleteAs, IComponentAutoCompleteAs<IInputTagsProps>>(
   function InputAutoComplete(
      {
         _handleInputChange,
         _openAutoComplete,
         _closeAutoComplete,
         _loading,
         onChange: _onChange,
         name,
         title,
         cleanAfterSelect = false,
         tags: tagsDefault,
         CustomTag = Tag,
         ...rest
      },
      ref,
   ): JSX.Element {
      const inputRef = useRef<HTMLInputElement>();

      const [focus, setFocus] = useState(false);
      const [error, setError] = useState('');
      const [_tags, setTags] = useImmer<any>([]);
      // usar interno ou state enviado
      const tags = tagsDefault || _tags;

      useDidUpdateEffect(() => {
         setTags((v) => {
            if (!_.isEqual(tagsDefault, v)) return tagsDefault;
         });
      }, [tagsDefault]);

      useDeepCompareEffectNoCheck(() => {
         if (_onChange) _onChange(_tags);
      }, [_tags]);

      useImperativeHandle(ref, () => ({
         onSelect(item) {
            setTags((v) => {
               if (v.find((tag) => _.isEqual(tag.value, item.value))) {
                  const tmp = [...v];
                  tmp.splice(
                     v.findIndex((tag) => _.isEqual(tag.value, item.value)),
                     1,
                  );
                  return tmp;
               }
               return [
                  ...v,
                  {
                     name: item.name,
                     value: item.value,
                  },
               ];
            });
         },
      }));

      function onInput(value: string): void {
         _handleInputChange(value);
         if (rest.onInput) rest.onInput(value);
      }

      function onFocus(e: any): void {
         _openAutoComplete();
         setFocus(true);
         if (rest.onFocus) rest.onFocus(e);
      }

      function onBlur(e: any): void {
         // _closeAutoComplete();
         setFocus(false);
         if (cleanAfterSelect) inputRef.current.value = '';
         if (rest.onBlur) rest.onBlur(e);
      }

      function onChange(v: any): void {
         setTags(() => Array.isArray(v) ? v : []);
      }

      function onError(err: string): void {
         setError(err);
      }

      function removeTag(tagValue: any): void {
         setTags((v) => {
            if (v.find((tag) => _.isEqual(tag.value, tagValue.value))) {
               const tmp = [...v];
               tmp.splice(
                  v.findIndex((tag) => _.isEqual(tag.value, tagValue.value)),
                  1,
               );
               return tmp;
            }

            return v;
         });
      }

      useEventListener('keydown.tab', () => {
         _closeAutoComplete();
      });

      return (
         <>
            {!!name && <UnformInput name={name} onChange={onChange} value={tags} onError={onError} />}

            {title && <div className={`input-title ${focus && 'focus'}`}>{title}</div>}

            <div
               className={classNames(['input-border', 'autocomplete-border', focus && 'focus', error && 'has-error'])}
            >
               {!!tags.length && (
                  <span className="tags">
                     {tags.map((tag, i) => (
                        <CustomTag key={`tag-${i}-${tag.name}`} tag={tag} index={i} removeTag={() => removeTag(tag)} />
                     ))}
                  </span>
               )}
               <Input
                  {...rest}
                  ref={inputRef}
                  onInput={onInput}
                  onFocus={onFocus}
                  onBlur={onBlur}
                  loading={_loading}
                  data-testid="autocomplete--input"
               />
            </div>

            {error && (
               <div className="error-input" data-testid="input-error">
                  {error}
               </div>
            )}
         </>
      );
   },
);

export function InputTags(props: IPropsAutoComplete<IInputTagsProps>): JSX.Element {
   const [_tags, setTags] = useState<IInputTagsTag[]>([]);
   // usar interno ou state enviado
   const tags = props.tags || _tags;

   function onChange(_tags: IInputTagsTag[]): void {
      setTags(_tags);
      if (props.onChange) props.onChange(_tags);
   }

   return (
      <S.Container>
         <AutocompletePure
            {...props}
            as={InputAutoComplete}
            onChange={onChange as any}
            renderRow={(name, value, active) => (
               <RenderRow
                  name={name}
                  value={value}
                  disabled={value.disabled}
                  active={active}
                  selected={!!tags.find((tag) => _.isEqual(tag.value, value))}
               />
            )}
            persistOpenAutoCompleteItemsAfterSelect
         />
      </S.Container>
   );
}

function Tag({ tag, index, removeTag }: any): JSX.Element {
   return (
      <div className="tag" onClick={() => removeTag && removeTag()} data-testid={`tag-${index}`}>
         <div className="name">{tag.name}</div>
         <div className="close-btn-container">
            <CloseBtn size={10} color="white" />
         </div>
      </div>
   );
}

const RenderRow = React.memo(function RenderRow({
   name,
   value,
   disabled,
   selected,
   active,
}: {
   name: string;
   value: any;
   disabled?: boolean;
   active: boolean;
   selected: boolean;
}): JSX.Element {
   return (
      <div className={`item-row ${active && 'active'} ${disabled && 'disabled'} ${selected && 'selected'}`}>
         <span className={`checkbox ${selected && 'active'}`}>
            <FontAwesomeIcon icon={faCheck} />
         </span>
         {name}
      </div>
   );
},
_.isEqual);
