/* eslint-disable @typescript-eslint/no-explicit-any */
'use client';

import { useEffect, useMemo, useState } from 'react';

import { useTranslations } from 'next-intl';

import { X } from 'lucide-react';
import { Control, useController } from 'react-hook-form';

import CreatorResultList from '@/components/creators/CreatorResultList';
import { Input } from '@/components/ui/input';
import { creatorIdentityMatchesQuery } from '@/utils/creatorIdentity';

import type { CreatorListData } from '@/types/Creator';

import { FieldWrapper } from './FieldWrapper';

type Creator = CreatorListData;

const CREATOR_SEARCH_MIN_QUERY_LENGTH = 3;

interface CreatorMultiSelectProps {
  control: Control<any>;
  name: string;
  label: string;
  creatorOptions: Creator[];
  required?: boolean;
  requiredNote?: string;
  helper?: string;
  placeholder?: string;
  // to store/retrieve creator objects
  creatorObjectsName?: string;
}

export const CreatorMultiSelect: React.FC<CreatorMultiSelectProps> = ({
  control,
  name,
  label,
  creatorOptions,
  required,
  requiredNote,
  helper,
  placeholder,
  creatorObjectsName,
}) => {
  const {
    field,
    fieldState: { error },
  } = useController({ control, name });

  const creatorObjectsField = useController({
    control,
    name: creatorObjectsName || `${name}Objects`,
  });

  const t = useTranslations('common');
  const [query, setQuery] = useState('');
  const trimmedQuery = useMemo(() => query.trim(), [query]);
  const isQueryTooShort = trimmedQuery.length < CREATOR_SEARCH_MIN_QUERY_LENGTH;
  const results = useMemo(
    () =>
      isQueryTooShort
        ? []
        : creatorOptions.filter((creator) => creatorIdentityMatchesQuery(creator, trimmedQuery)),
    [creatorOptions, isQueryTooShort, trimmedQuery]
  );
  const creatorsById = useMemo(() => {
    const map = new Map<number, Creator>();
    creatorOptions.forEach((creator) => map.set(creator.id, creator));
    return map;
  }, [creatorOptions]);

  const selectedObjects = useMemo<Creator[]>(
    () => (Array.isArray(creatorObjectsField.field.value) ? creatorObjectsField.field.value : []),
    [creatorObjectsField.field.value]
  );

  useEffect(() => {
    const selectedIds: number[] = Array.isArray(field.value) ? field.value : [];
    if (selectedIds.length === 0) return;

    const freshObjects = selectedIds
      .map((id) => creatorsById.get(id))
      .filter((creator): creator is Creator => Boolean(creator));
    if (freshObjects.length === 0) return;

    const currentIds = selectedObjects.map((creator) => creator.id).sort((a, b) => a - b);
    const freshIds = freshObjects.map((creator) => creator.id).sort((a, b) => a - b);

    const isSameSelection =
      currentIds.length === freshIds.length &&
      currentIds.every((id, index) => id === freshIds[index]);

    if (isSameSelection) return;
    creatorObjectsField.field.onChange(freshObjects);
  }, [creatorObjectsField.field, creatorsById, field.value, selectedObjects]);

  const addCreator = (creator: Creator) => {
    const selectedIds: number[] = Array.isArray(field.value) ? field.value : [];
    if (!selectedIds.includes(creator.id)) {
      field.onChange([...selectedIds, creator.id]);

      const updatedObjects = selectedObjects.some((prev) => prev.id === creator.id)
        ? selectedObjects
        : [...selectedObjects, creator];

      creatorObjectsField.field.onChange(updatedObjects);
    }
    setQuery('');
  };

  const removeCreator = (id: number) => {
    const selectedIds: number[] = Array.isArray(field.value) ? field.value : [];
    field.onChange(selectedIds.filter((creatorId) => creatorId !== id));
    creatorObjectsField.field.onChange(selectedObjects.filter((creator) => creator.id !== id));
  };

  const findCreator = (id: number) =>
    selectedObjects.find((creator) => creator.id === id) || creatorsById.get(id);

  return (
    <FieldWrapper
      label={label}
      required={required}
      requiredNote={requiredNote}
      helper={helper}
      error={error?.message}
    >
      {Array.isArray(field.value) && field.value.length > 0 ? (
        <div className="creator-chips mb-2 flex flex-wrap gap-2">
          {field.value.map((id: number) => {
            const creator = findCreator(id);

            return (
              <div
                key={id}
                className="creator-chip mb-2 flex items-center gap-2 bg-mma-blue px-3 py-2 text-sm font-semibold text-white"
              >
                <span>{creator?.nev}</span>
                <button
                  type="button"
                  onClick={() => removeCreator(id)}
                  className="hover:opacity-70"
                >
                  <X className="h-4 w-4" />
                </button>
              </div>
            );
          })}
        </div>
      ) : null}

      <Input
        placeholder={placeholder}
        value={query}
        onChange={(event) => setQuery(event.target.value)}
        className="creator-input"
      />

      {!isQueryTooShort ? (
        <div
          role="listbox"
          className="creator-results mt-2 max-h-64 overflow-auto border border-mma-blue/10 bg-white"
        >
          {results.length === 0 ? (
            <div className="p-3 text-sm text-gray-500">{t('noResult')}</div>
          ) : (
            <CreatorResultList
              creators={results}
              onSelect={addCreator}
              emptyLabel={t('noResult')}
              getKey={(creator) => creator.id}
              isSelected={(creator) =>
                Array.isArray(field.value) && field.value.includes(creator.id)
              }
              itemClassName={({ selected }) =>
                `creator-result-item cursor-pointer ${
                  selected ? 'bg-mma-cyan/20' : 'hover:bg-mma-cyan/10'
                }`
              }
            />
          )}
        </div>
      ) : null}
    </FieldWrapper>
  );
};
