import { Fragment, VNode, h } from "preact";
import { useRef, useState } from "preact/hooks";
import { useTranslationContext } from "../../index.browser.js";
import { UIFormProps } from "../FormProvider.js";
import { noHandlerPropsAndNoContextForField } from "./InputArray.js";
import { ChoiceS } from "./InputChoiceStacked.js";
import { LabelWithTooltipMaybeRequired } from "./InputLine.js";

/**
 * @type ChoiceVal result type of the choice (for example: "choiceA" | "choiceB")
 */
export function InputSelectMultiple<ChoiceVal>(
  props: {
    choices: ChoiceS<ChoiceVal>[];
    unique?: boolean;
    max?: number;
  } & UIFormProps<ChoiceVal>,
): VNode {
  const {
    converter,
    label,
    choices,
    placeholder,
    tooltip,
    help,
    required,
    hidden,
    unique,
    max,
  } = props;
  const { i18n } = useTranslationContext();
  const { value, onChange } =
    props.handler ?? noHandlerPropsAndNoContextForField(props.name);

  const [filter, setFilter] = useState<string | undefined>(undefined);
  const [dirty, setDirty] = useState<boolean>();

  if (hidden) {
    return <Fragment />;
  }
  const regex = new RegExp(`.*${filter}.*`, "i");
  const choiceMap = choices.reduce(
    (prev, curr) => {
      return { ...prev, [curr.value as string]: curr.label };
    },
    {} as Record<string, string>,
  );

  const inputRef = useRef<HTMLInputElement>(null);

  const list = (value ?? []) as string[];
  const filteredChoices =
    filter === undefined
      ? undefined
      : choices.filter((v) => {
          const match = regex.test(v.label);
          if (!unique) return match;
          return match && list.indexOf(v.value as string) === -1;
        });
  return (
    <div class="sm:col-span-6">
      <LabelWithTooltipMaybeRequired
        label={label}
        required={required}
        tooltip={tooltip}
        name={props.name as string}
      />

      {!props.disabled && (
        <div class="relative mt-2">
          <input
            ref={inputRef}
            id="combobox"
            type="text"
            value={filter ?? ""}
            autoComplete="off"
            onChange={(e) => {
              setFilter(e.currentTarget.value);
              setDirty(true);
            }}
            onBlur={(e) => {
              setFilter(undefined);
            }}
            onFocus={(e) => {
              setFilter("");
            }}
            onClick={(e) => {
              setFilter("");
            }}
            placeholder={placeholder}
            class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
            role="combobox"
            aria-controls="options"
            aria-expanded="false"
          />
          <button
            type="button"
            disabled={props.disabled}
            onMouseDown={(e) => {
              // Input element should not lose focus
              e.preventDefault();
            }}
            onClick={(e) => {
              setFilter(filter === undefined ? "" : undefined);
              setDirty(true);
              inputRef.current?.focus();
            }}
            class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"
          >
            <svg
              class="h-5 w-5 text-gray-400"
              viewBox="0 0 20 20"
              fill="currentColor"
              aria-hidden="true"
            >
              <path
                fill-rule="evenodd"
                d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z"
                clip-rule="evenodd"
              />
            </svg>
          </button>

          {filter === undefined ? undefined : filteredChoices === undefined ||
            !filteredChoices.length ? (
            <ul
              class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
              id="options"
              role="listbox"
            >
              <li class="relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600">
                <span class="block truncate font-bold">
                  <i18n.Translate>No element found</i18n.Translate>
                </span>
              </li>
            </ul>
          ) : (
            <ul
              class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
              id="options"
              role="listbox"
            >
              {filteredChoices.map((v, idx) => {
                return (
                  <li
                    key={idx}
                    class="relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600"
                    id="option-0"
                    role="option"
                    onMouseDown={(e) => {
                      // Input element should not lose focus
                      e.preventDefault();
                    }}
                    onClick={() => {
                      setFilter(undefined);
                      if (unique && list.indexOf(v.value as string) !== -1) {
                        return;
                      }
                      if (max !== undefined && list.length >= max) {
                        return;
                      }
                      const newValue = [...list];
                      newValue.push(v.value as string);
                      onChange(newValue as any);
                    }}
                  >
                    <span class="block truncate">{v.label}</span>
                  </li>
                );
              })}
            </ul>
          )}
        </div>
      )}
      {list.map((v, idx) => {
        return (
          <span
            key={idx}
            class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mt-2 mr-2 text-xs font-medium text-gray-600"
          >
            {choiceMap[v]}
            <button
              type="button"
              disabled={props.disabled}
              onClick={() => {
                const newValue = [...list];
                newValue.splice(idx, 1);
                onChange(newValue as any);
                setFilter(undefined);
              }}
              class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
            >
              <span class="sr-only">
                <i18n.Translate>Remove</i18n.Translate>
              </span>
              <svg
                viewBox="0 0 14 14"
                class="h-5 w-5 stroke-gray-700/50 group-hover:stroke-gray-700/75"
              >
                <path d="M4 4l6 6m0-6l-6 6" />
              </svg>
              <span class="absolute -inset-1"></span>
            </button>
          </span>
        );
      })}
      {help && (
        <p class="mt-2 text-sm text-gray-500" id="email-description">
          {help}
        </p>
      )}
    </div>
  );
}
