import React, { useEffect, useState, useCallback } from "react";
import Select from "../common/Select";
import Option from "../common/option";
import { GeneralIdRef, MakeGeneralIdRef } from "../../utils/GeneralIdRef";
import glossariesService, {
  CustomFieldValue,
  SystemGlossaries,
} from "../../modules/manager/glossary/services/glossaryService";
import MultiSelect from "../common/MultiSelect";

interface GlossaryPickerProps {
  includeLabel?: boolean;
  name: string;
  label: string;
  rootItem?: GeneralIdRef;
  error?: string;
  values: CustomFieldValue[];
  maxEntries?: number;
  onChange?: (name: string, values: CustomFieldValue[]) => void;
}

export default function GlossaryPicker({
  includeLabel,
  name,
  label,
  rootItem,
  error,
  values,
  maxEntries,
  onChange,
}: GlossaryPickerProps) {
  const [options, setOptions] = useState<Option[]>([]);
  const [selectedOptions, setSelectedOptions] = useState<Option[]>([]);

  useEffect(() => {
    async function load() {
      const actualRootItem = rootItem ?? SystemGlossaries;
      const glossary = await glossariesService.getGlossaryItem(actualRootItem);

      if (glossary) {
        const opts: Option[] = glossary.children.map(
          (x: { id: any; name: any }) => ({
            _id: x.id,
            name: x.name,
          }),
        );

        const selected: Option[] = [];

        if (values) {
          for (const option of values) {
            const foundOption = opts.filter(
              (x) =>
                Number(x._id) === Number((option.value as GeneralIdRef).id),
            )[0];
            if (foundOption) selected.push(foundOption);
          }
        }

        setOptions(opts);
        setSelectedOptions(selected);
      }
    }

    load();
  }, [rootItem, values]);

  const doOnChange = useCallback(
    (newSelectedOptions: Option[]) => {
      const vals: CustomFieldValue[] = newSelectedOptions.map((x) => ({
        value: MakeGeneralIdRef(x._id as unknown as bigint),
        displayValue: x.name,
      }));

      if (onChange) onChange(name, vals);
    },
    [onChange, name],
  );

  const handleChange = useCallback(
    (e: React.ChangeEvent<HTMLSelectElement>) => {
      const input = e.currentTarget;
      const id: number = Number(input.value);

      const newSelected = options.filter((x) => x._id === id);
      setSelectedOptions(newSelected);
      doOnChange(newSelected);
    },
    [options, doOnChange],
  );

  const handleAdd = useCallback(
    (item: Option) => {
      const newSelected = [...selectedOptions, item];
      setSelectedOptions(newSelected);
      doOnChange(newSelected);
    },
    [selectedOptions, doOnChange],
  );

  const handleDelete = useCallback(
    (item: Option) => {
      const newSelected = selectedOptions.filter((x) => x !== item);
      setSelectedOptions(newSelected);
      doOnChange(newSelected);
    },
    [selectedOptions, doOnChange],
  );

  if (maxEntries === 1) {
    const value = selectedOptions[0]?._id;
    return (
      <Select
        includeLabel={includeLabel}
        name={name}
        label={label}
        error={error}
        value={value}
        options={options}
        includeBlankFirstEntry={true}
        onChange={handleChange}
      />
    );
  } else {
    return (
      <MultiSelect
        includeLabel={includeLabel}
        name={name}
        label={label}
        error={error}
        options={options}
        selectedOptions={selectedOptions}
        onAdd={handleAdd}
        onDelete={handleDelete}
      />
    );
  }
}
