import { useCallback, useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { type UseInfiniteQueryResult } from 'react-query';

import HuFormInputClassic from '@material-hu/components/design-system/Inputs/Classic/form';
import HuFormDatePicker from '@material-hu/components/design-system/Inputs/DatePicker/form';

import { type CustomField, CustomFieldTypes } from 'src/types/instance';
import { type SegmentationType } from 'src/types/user';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  dynamicPrefix,
  EqualityOperator,
  type FieldTypes,
  RequestField,
  segmentationPrefix,
  UserGeneralFieldsIds,
  ValueComponentType,
} from 'src/components/Condition/components/constants';

import MenuSelect, { type HuMenuItem } from '../MenuSelect';

type FieldProps = {
  componentType: ValueComponentType;
  items?: HuMenuItem[];
  infiniteQuery?: UseInfiniteQueryResult<unknown>;
  isLoading?: boolean;
  isFetching?: boolean;
  hasCheckbox?: boolean;
  hasAvatar?: boolean;
  customItems?: () => HuMenuItem[];
  search?: string;
  setSearch?: (search: string) => void;
  onScrollEnd?: () => void;
};

/**
 * Renders the appropriate value input (dropdown, date picker, text)
 * based on the selected condition field and operator.
 */
const ValueSelector = ({
  index,
  name,
  users,
  agents,
  states,
  categories,
  departments,
  jobs,
  usersInfiniteQuery,
  agentsInfiniteQuery,
  categoriesInfiniteQuery,
  departmentsInfiniteQuery,
  jobsInfiniteQuery,
  dynamicFields,
  isLoadingStates,
  search,
  setSearch,
  segmentationGroups,
}: {
  index: number;
  name: string;
  users: HuMenuItem[];
  agents: HuMenuItem[];
  states: HuMenuItem[];
  categories: HuMenuItem[];
  departments: HuMenuItem[];
  jobs: HuMenuItem[];
  usersInfiniteQuery: UseInfiniteQueryResult<unknown>;
  agentsInfiniteQuery: UseInfiniteQueryResult<unknown>;
  categoriesInfiniteQuery: UseInfiniteQueryResult<unknown>;
  departmentsInfiniteQuery: UseInfiniteQueryResult<unknown>;
  jobsInfiniteQuery: UseInfiniteQueryResult<unknown>;
  dynamicFields: CustomField[];
  isLoadingStates: boolean;
  search: string;
  setSearch: (search: string) => void;
  segmentationGroups?: SegmentationType[];
}) => {
  const { t } = useLokaliseTranslation(['backoffice_only']);
  const { watch } = useFormContext();

  const field = watch(`${name}[${index}].field`);
  const equalityOperator = watch(`${name}[${index}].equalityOperator`);

  // Operators that require no value input (empty/not-empty checks)
  const noField =
    !field ||
    [
      EqualityOperator.IS_EMPTY,
      EqualityOperator.IS_NOT_EMPTY,
      EqualityOperator.ARRAY_IS_EMPTY,
      EqualityOperator.ARRAY_IS_NOT_EMPTY,
    ].includes(equalityOperator);

  const isFieldType = (
    fieldType: RequestField | FieldTypes | UserGeneralFieldsIds,
  ) => field === fieldType && !noField;

  const isDynamicFieldType = (fieldType: CustomFieldTypes) =>
    dynamicFieldData?.type === fieldType && !noField;

  const isDynamicArrayFieldType = () =>
    dynamicFieldData?.type &&
    [
      CustomFieldTypes.STRING_LIST,
      CustomFieldTypes.NUMBER_LIST,
      CustomFieldTypes.MULTIPLE_OPTION,
    ].includes(dynamicFieldData?.type) &&
    !noField;

  // Dynamic (custom profile) field resolution
  const isDynamic = field?.includes(dynamicPrefix);
  const dynamicFieldData = dynamicFields.find(f => f.id === field);
  const isDynamicOptions = isDynamic && dynamicFieldData?.options;
  const isDynamicNoOptions = isDynamic && !dynamicFieldData?.options;

  // Segmentation field resolution: extract group ID from the field key
  const isSegmentation =
    typeof field === 'string' && field.startsWith(segmentationPrefix);
  const segmentationGroupId = isSegmentation
    ? Number(field.replace(segmentationPrefix, ''))
    : null;
  const segmentationGroup = segmentationGroups?.find(
    g => g.id === segmentationGroupId,
  );

  const SEGMENTATION_PAGE_SIZE = 30;
  const [segmentationVisibleCount, setSegmentationVisibleCount] = useState(
    SEGMENTATION_PAGE_SIZE,
  );

  const allSegmentationItems: HuMenuItem[] =
    segmentationGroup?.items?.map(item => ({
      id: item.id,
      label: item.name,
    })) || [];

  // Current form value for this row, normalised to an array of IDs
  const value = watch(`${name}[${index}].value`);
  const selectedValueIds: HuMenuItem['id'][] = (() => {
    if (Array.isArray(value)) return value;
    if (value) return [value];
    return [];
  })();

  /**
   * Returns paginated segmentation items, always including any
   * currently-selected items at the front so MenuSelect can
   * resolve their labels for the button text (even after refresh).
   */
  const getSegmentationItems = (): HuMenuItem[] => {
    const selectedIdSet = new Set(selectedValueIds);
    const selectedItems = allSegmentationItems.filter(item =>
      selectedIdSet.has(item.id),
    );
    const paginated = allSegmentationItems
      .filter(item => !selectedIdSet.has(item.id))
      .slice(0, segmentationVisibleCount);
    return [...selectedItems, ...paginated];
  };

  // biome-ignore lint/correctness/useExhaustiveDependencies: reset pagination when field changes
  useEffect(() => {
    setSegmentationVisibleCount(SEGMENTATION_PAGE_SIZE);
  }, [field]);

  const handleSegmentationScrollEnd = useCallback(() => {
    setSegmentationVisibleCount(prev =>
      Math.min(prev + SEGMENTATION_PAGE_SIZE, allSegmentationItems.length),
    );
  }, [allSegmentationItems.length]);

  const getDynamicOptions = (): HuMenuItem[] =>
    dynamicFieldData?.options?.map((option: string) => ({
      id: option,
      label: option,
    })) || [];

  /**
   * Maps the selected condition field to the appropriate value
   * component type and props (items, search, infinite scroll, etc.).
   */
  const getFieldConfig = (): FieldProps | null => {
    if (noField) return { componentType: ValueComponentType.DISABLED_MENU };

    if (isFieldType(RequestField.AGENT)) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        items: agents,
        isLoading: agentsInfiniteQuery.isLoading,
        isFetching: agentsInfiniteQuery.isFetching,
        infiniteQuery: agentsInfiniteQuery,
        hasCheckbox: true,
        hasAvatar: true,
        search,
        setSearch,
      };
    }

    if (
      isFieldType(RequestField.REQUESTER) ||
      isFieldType(UserGeneralFieldsIds.DIRECT_BOSS) ||
      isDynamicFieldType(CustomFieldTypes.USER_LIST)
    ) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        items: users,
        isLoading: usersInfiniteQuery.isLoading,
        isFetching: usersInfiniteQuery.isFetching,
        infiniteQuery: usersInfiniteQuery,
        hasCheckbox: true,
        hasAvatar: true,
        search,
        setSearch,
      };
    }

    if (isFieldType(RequestField.STATUS)) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        items: states || [],
        isLoading: isLoadingStates,
        hasCheckbox: true,
      };
    }

    if (isFieldType(RequestField.CATEGORY)) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        items: categories,
        infiniteQuery: categoriesInfiniteQuery,
        isLoading: categoriesInfiniteQuery.isLoading,
        hasCheckbox: true,
        hasAvatar: true,
      };
    }

    if (isFieldType(UserGeneralFieldsIds.DEPARTMENT)) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        items: departments,
        infiniteQuery: departmentsInfiniteQuery,
        isLoading: departmentsInfiniteQuery.isLoading,
        hasCheckbox: true,
        search,
        setSearch,
      };
    }

    if (isFieldType(UserGeneralFieldsIds.JOB_POSITION)) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        items: jobs,
        infiniteQuery: jobsInfiniteQuery,
        isLoading: jobsInfiniteQuery.isLoading,
        hasCheckbox: true,
        search,
        setSearch,
      };
    }

    if (
      isFieldType(RequestField.UPDATED_AT) ||
      isFieldType(UserGeneralFieldsIds.BIRTHDATE) ||
      isFieldType(UserGeneralFieldsIds.HIRING_DATE) ||
      isDynamicFieldType(CustomFieldTypes.DATE)
    ) {
      return { componentType: ValueComponentType.DATE_PICKER };
    }

    // Segmentation items are paginated locally; search/setSearch are
    // intentionally omitted to avoid the useHydratedUsers path in
    // MenuSelect, which would fail for non-user IDs.
    if (isSegmentation && !noField) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        customItems: getSegmentationItems,
        hasCheckbox: true,
        onScrollEnd: handleSegmentationScrollEnd,
      };
    }

    if (isDynamicOptions || isDynamicArrayFieldType()) {
      return {
        componentType: ValueComponentType.MENU_SELECT,
        customItems: getDynamicOptions,
        hasCheckbox: true,
      };
    }

    if (isDynamicNoOptions)
      return { componentType: ValueComponentType.TEXT_INPUT };

    return null;
  };

  // "includes" operators allow multi-select (up to 10)
  const maxSelection = [
    EqualityOperator.IS_IN,
    EqualityOperator.IS_NOT_IN,
    EqualityOperator.ARRAY_IS_IN,
    EqualityOperator.ARRAY_IS_NOT_IN,
  ].includes(equalityOperator)
    ? 10
    : 1;

  const isDisabled =
    !watch(`${name}[${index}].equalityOperator`) ||
    !watch(`${name}[${index}].field`);

  const fieldConfig = getFieldConfig();

  if (!fieldConfig) return null;

  const commonProps = {
    name: `${name}[${index}].value`,
    disabled: isDisabled,
  };

  const menuSelectProps = {
    title: t('backoffice_only:condition.value'),
    maxSelection,
    maxDisplayItems: 1,
    isDisabled,
    ...commonProps,
  };

  switch (fieldConfig.componentType) {
    case ValueComponentType.MENU_SELECT: {
      const menuSelectComponentProps = {
        ...menuSelectProps,
        items: fieldConfig.customItems
          ? fieldConfig.customItems()
          : fieldConfig.items || [],
        ...(fieldConfig.infiniteQuery && {
          infiniteQuery: fieldConfig.infiniteQuery,
        }),
        ...(fieldConfig.isLoading !== undefined && {
          isLoading: fieldConfig.isLoading,
        }),
        ...(fieldConfig.isFetching !== undefined && {
          isFetching: fieldConfig.isFetching,
        }),
        ...(fieldConfig.hasCheckbox && {
          hasCheckbox: fieldConfig.hasCheckbox,
        }),
        ...(fieldConfig.hasAvatar && { hasAvatar: fieldConfig.hasAvatar }),
        ...(fieldConfig.search && { search: fieldConfig.search }),
        ...(fieldConfig.setSearch && { setSearch: fieldConfig.setSearch }),
        ...(fieldConfig.onScrollEnd && {
          onScrollEnd: fieldConfig.onScrollEnd,
        }),
      };

      return <MenuSelect {...menuSelectComponentProps} />;
    }

    case ValueComponentType.DATE_PICKER:
      return (
        <HuFormDatePicker
          {...commonProps}
          inputProps={{
            size: 'small',
            sx: { flex: 1 },
          }}
        />
      );

    case ValueComponentType.TEXT_INPUT:
      return (
        <HuFormInputClassic
          {...commonProps}
          inputProps={{
            hasCounter: false,
            size: 'small',
            sx: { flex: 1, maxHeight: '40px', overflow: 'hidden' },
            disabled: isDisabled,
            type: dynamicFieldData?.type || CustomFieldTypes.STRING,
          }}
        />
      );

    case ValueComponentType.DISABLED_MENU:
      return (
        <MenuSelect
          title={t('backoffice_only:condition.value')}
          name={`${name}[${index}].value`}
          isDisabled
        />
      );

    default:
      return null;
  }
};

export default ValueSelector;
