import React, { useState, useRef, useEffect } from 'react';
import styles from './SelectInput.module.css';

interface Option {
  label: string;
  value: any;
}

interface Props {
  onChange: (value: string | string[] | null) => void;
  options: Option[];
  isMultiple?: boolean;
  value?: string | string[];
}

export default function SelectInput({
  options,
  isMultiple = false,
  onChange,
  value = [],
}: Props): JSX.Element {
  const [selected, setSelected] = useState<string[]>([]);
  const [filteredOptions, setFilteredOptions] = useState<Props['options']>([]);
  const [isOptionsOpen, setIsOptionsOpen] = useState<boolean>(false);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    setFilteredOptions(options);
  }, [options]);

  useEffect(() => {
    if (selected.length === 0) {
      onChange(null);
      return;
    }

    onChange(isMultiple ? selected : selected[0]);
  }, [selected]);

  const handleFocusInput = (): void => {
    setIsOptionsOpen(true);
    inputRef.current?.focus();
  };

  const handleAddElement = (item: any): void => {
    setSelected((prev) => {
      if (isMultiple) {
        return [...prev, item];
      }
      return [item];
    });
    setIsOptionsOpen(false);

    if (inputRef.current === null) return;

    inputRef.current.value = '';
  };

  const handleRemoveElement = (idx: number): void => {
    setIsOptionsOpen(false);
    setSelected((prev) => {
      prev.splice(idx, 1);

      return [...prev];
    });
  };

  const handleLooseFocus = (e: React.FocusEvent<HTMLDivElement>): void => {
    if (!e.currentTarget.contains(e.relatedTarget)) {
      // Not triggered when swapping focus between children
      setIsOptionsOpen(false);
    }
  };

  const handleFilterOptions = ({
    target,
  }: React.ChangeEvent<HTMLInputElement>): void => {
    if (target.value === '') {
      setFilteredOptions(options);
      return;
    }

    const newOptions = options.filter(
      (item) =>
        item.label.toLowerCase().search(target.value.toLowerCase()) !== -1,
    );
    setFilteredOptions(newOptions);
  };

  return (
    <div className={styles.wrapper} onBlur={handleLooseFocus}>
      <div
        className={styles.input}
        onClick={() => {
          handleFocusInput();
        }}
      >
        {selected.map((item, idx) => (
          <div className={styles.selectedItem + ' hstack'} key={idx}>
            <div>{item}</div>
            <div
              className={styles.deleteItem}
              onClick={() => {
                handleRemoveElement(idx);
              }}
            >
              {'X'}
            </div>
          </div>
        ))}
        <input
          ref={inputRef}
          className={styles.realInput}
          type="text"
          onChange={handleFilterOptions}
        />
      </div>
      <button
        onClick={() => {
          onChange(null);
          setSelected([]);
        }}
      >
        X
      </button>
      <div className={styles.optionList} hidden={!isOptionsOpen}>
        {filteredOptions.map((item, idx) => (
          <button
            className={styles.optionItem}
            key={idx}
            disabled={selected.includes(item.value)}
            onClick={() => {
              handleAddElement(item.value);
            }}
          >
            {item.label}
          </button>
        ))}
      </div>
    </div>
  );
}
