import { useRef, useState } from 'react';

import ConditionLine from '@composed-components/ConditionLine';
import {
  type ConditionLineProps,
  type ConditionLineValues,
  type DefaultItemType,
} from '@composed-components/ConditionLine/types';
import InfiniteListLoader from '@composed-components/InfiniteListLoader';
import DefaultList from '@composed-components/MenuListItems/components/DefaultList';
import { type BaseListRendererProps } from '@composed-components/MenuListItems/types';
import { Stack } from '@mui/material';

import { type DynamicItemsConfig, type DynamicItemsResult } from '../types';

type DynamicConditionLineProps<
  FieldItemType extends DefaultItemType,
  ValueItemType extends DefaultItemType,
> = {
  condition: ConditionLineValues<FieldItemType, ValueItemType>;
  allConditions: ConditionLineValues<FieldItemType, ValueItemType>[];
  index: number;
  dynamicItems: DynamicItemsConfig<FieldItemType, ValueItemType>;
  conditionLineProps?: Partial<
    ConditionLineProps<FieldItemType, ValueItemType>
  >;
  onChange: (
    condition: ConditionLineValues<FieldItemType, ValueItemType>,
  ) => void;
  onDelete: () => void;
  disabled?: boolean;
};

const InfiniteScrollList = <ItemType extends DefaultItemType>({
  result,
  ...listProps
}: BaseListRendererProps<ItemType> & {
  result: DynamicItemsResult<ItemType>;
}) => {
  const containerRef = useRef<HTMLDivElement>(null);

  return (
    <Stack
      ref={containerRef}
      sx={{ maxHeight: '224px', overflow: 'auto' }}
    >
      <DefaultList {...listProps} />
      {result.hasNextPage && result.fetchNextPage && (
        <Stack sx={{ alignItems: 'center', py: 1 }}>
          <InfiniteListLoader
            onLoadMore={result.fetchNextPage}
            containerRef={containerRef}
            loading={result.isFetchingNextPage}
          />
        </Stack>
      )}
    </Stack>
  );
};

/**
 * Wraps a {@link ConditionLine} with per-line lazy loading of field and value items.
 * Each instance manages its own search state and calls the dynamic item hooks independently.
 */
const DynamicConditionLine = <
  FieldItemType extends DefaultItemType,
  ValueItemType extends DefaultItemType,
>({
  condition,
  allConditions,
  index,
  dynamicItems,
  conditionLineProps,
  onChange,
  onDelete,
  disabled,
}: DynamicConditionLineProps<FieldItemType, ValueItemType>) => {
  const [fieldSearch, setFieldSearch] = useState('');
  const [valueSearch, setValueSearch] = useState('');

  const handleFieldSearchChange = (value?: string) =>
    setFieldSearch(value ?? '');
  const handleValueSearchChange = (value?: string) =>
    setValueSearch(value ?? '');

  const excludeFieldIds = allConditions
    .filter((_, i) => i !== index)
    .map(c => c.field?.id)
    .filter((id): id is number => id != null);

  const fieldResult = dynamicItems.useFieldItems({
    excludeFieldIds,
    q: fieldSearch || undefined,
  });

  const fieldId = condition.field?.id ?? null;
  const hasFieldId = fieldId != null;

  const valueResult = dynamicItems.useValueItems({
    fieldId,
    q: valueSearch || undefined,
  });

  const handleChange = (
    newCondition: ConditionLineValues<FieldItemType, ValueItemType>,
  ) => {
    if (newCondition.field?.id !== condition.field?.id) {
      onChange({ ...newCondition, value: [] });
      setValueSearch('');
      return;
    }
    onChange(newCondition);
  };

  return (
    <ConditionLine
      {...conditionLineProps}
      value={condition}
      disabled={disabled || conditionLineProps?.disabled}
      onDelete={onDelete}
      onChange={handleChange}
      fieldSelectorItems={fieldResult.items}
      valueSelectorItems={valueResult.items}
      slotProps={{
        ...conditionLineProps?.slotProps,
        fieldSelector: {
          ...conditionLineProps?.slotProps?.fieldSelector,
          loading: fieldResult.loading,
          onSearchChange: handleFieldSearchChange,
          renderList: fieldResult.hasNextPage
            ? props => (
                <InfiniteScrollList
                  {...props}
                  result={fieldResult}
                />
              )
            : conditionLineProps?.slotProps?.fieldSelector?.renderList,
        },
        valueSelector: {
          ...conditionLineProps?.slotProps?.valueSelector,
          loading: !hasFieldId ? false : valueResult.loading,
          disabled: !hasFieldId,
          onSearchChange: handleValueSearchChange,
          renderList: valueResult.hasNextPage
            ? props => (
                <InfiniteScrollList
                  {...props}
                  result={valueResult}
                />
              )
            : conditionLineProps?.slotProps?.valueSelector?.renderList,
        },
      }}
    />
  );
};

export default DynamicConditionLine;
