import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {ListRenderItem, ScrollView, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {IconPlus} from '@tabler/icons-react-native';
import {
  ListRow,
  Dialog,
  Typography,
  TextInputType,
  InputCore,
  InputBox,
  INPUT_ICONS,
  Chip,
  Check,
  InputClassic,
  BottomSheetFlatList,
  Button,
  useInputController,
} from '@components';
import {useSafeAreaBottomPadding} from '@hooks/useSafeAreaBottomPadding';
import {useTheme} from '@shared/theme';
import {DEFAULT_THRESHOLD} from '@shared/constants';

import {
  InputApplyClearSelectOption,
  InputApplyClearSelectProps,
  OnChangeCallback,
  InputApplyClearSelectControllerProps,
} from './interfaces';
import {styles} from './styles';

const DEFAULT_SNAP_POINTS = ['40%', '60%', '90%'];

/** Snap points compactos en modo creación para que el teclado no expanda el sheet. */
const CREATE_MODE_SNAP_POINTS = ['35%'];

const LIST_FOOTER_PADDING = 150;

const keyExtractor = <T,>(item: InputApplyClearSelectOption<T>) => `${item.id}`;

const filterRule = <T,>(
  item: InputApplyClearSelectOption<T>,
  filterText: string,
) => item.label.toLowerCase().includes(filterText.toLowerCase());

export function InputApplyClearSelect<T = number>({
  label,
  helper,
  isError,
  isSuccess,
  disabled,
  filterable,
  searchPlaceholder,
  options,
  enableDynamicSizing,
  onClose,
  onChange,
  placeholder,
  value,
  createButtonLabel,
  createInputPlaceholder,
  snapPoints,
  withCreateButton,
  onCreatePress,
  onAddOption,
  onEndReached,
  onFilterText,
  ListEmptyComponent,
  size,
  modalTitleNumberOfLines,
  menuTitle,
  showCount,
  keyboardType = 'default',
}: InputApplyClearSelectProps<T>) {
  const {t} = useTranslation();
  const {theme, iconSizes} = useTheme();
  const [focused, setFocused] = useState(false);
  const [newSelectedItems, setNewSelectedItems] = useState<T[]>([]);
  const [pendingAddedOptions, setPendingAddedOptions] = useState<
    InputApplyClearSelectOption<T>[]
  >([]);
  const [isCreatingMode, setIsCreatingMode] = useState(false);
  const [newOptionLabel, setNewOptionLabel] = useState('');
  const createInputRef = useRef<TextInputType>(null);

  const paddingBottom = useSafeAreaBottomPadding({extra: LIST_FOOTER_PADDING});

  const hasInlineCreate = Boolean(withCreateButton && onAddOption);

  /** Normalize value to array so multiselect (e.g. USER_LIST) works when form returns undefined or a single item. */
  const arrayValue = useMemo(
    () =>
      Array.isArray(value)
        ? value
        : value !== undefined && value !== null
        ? [value as T]
        : [],
    [value],
  );

  useEffect(() => {
    if (isCreatingMode && focused) {
      const id = setTimeout(() => createInputRef.current?.focus(), 100);
      return () => clearTimeout(id);
    }
  }, [isCreatingMode, focused]);

  const color = disabled
    ? theme.text.neutral.disabled
    : theme.text.neutral.default;

  const effectiveOptions = useMemo(() => {
    const base = [...options, ...pendingAddedOptions];
    const byId = new Map(base.map(o => [o.id, o]));
    const fromSelected = (newSelectedItems ?? []).filter(
      id => !byId.has(id),
    ) as InputApplyClearSelectOption<T>[];
    const synthetic = fromSelected.map(id => ({
      id,
      label: String(id),
    })) as InputApplyClearSelectOption<T>[];
    return [...base, ...synthetic];
  }, [options, pendingAddedOptions, newSelectedItems]);

  const optionsForChips = useMemo(() => {
    const byId = new Map(options.map(o => [o.id, o]));
    const fromValue = arrayValue.filter(
      id => !byId.has(id),
    ) as InputApplyClearSelectOption<T>[];
    const synthetic = fromValue.map(id => ({
      id,
      label: String(id),
    })) as InputApplyClearSelectOption<T>[];
    return [...options, ...synthetic];
  }, [options, arrayValue]);

  const itemsSelected = useMemo(
    () =>
      optionsForChips.reduce((prev, current) => {
        const index = arrayValue.findIndex(e => e === current.id);
        if (index > -1) {
          prev[index] = current;
        }
        return prev;
      }, [] as InputApplyClearSelectOption<T>[]),
    [optionsForChips, arrayValue],
  );

  const effectiveHelper = showCount
    ? t('profile.total_options', {
        count: arrayValue.length,
      })
    : helper;

  const onInputPress = () => {
    setFocused(true);
    setPendingAddedOptions([]);
    setNewSelectedItems([...arrayValue]);
  };

  const onItemRemove = (id: T) => () => {
    const newValue = arrayValue.filter(element => element !== id);
    onChange?.(newValue);
  };

  const onModalClose = () => {
    setFocused(false);
    setIsCreatingMode(false);
    setNewOptionLabel('');
    setPendingAddedOptions([]);
    onClose?.();
  };

  const onGoBackFromCreate = useCallback(() => {
    setIsCreatingMode(false);
    setNewOptionLabel('');
  }, []);

  const onCreateButtonPress = useCallback(() => {
    if (hasInlineCreate) {
      setIsCreatingMode(true);
      setNewOptionLabel('');
    } else {
      onCreatePress?.();
    }
  }, [hasInlineCreate, onCreatePress]);

  const onPressAddNewOption = useCallback(async () => {
    const trimmed = newOptionLabel.trim();
    if (!trimmed || !onAddOption) return;
    try {
      const newOption = await Promise.resolve(onAddOption(trimmed));
      setPendingAddedOptions(prev => [...prev, newOption]);
      setNewSelectedItems(prev => [...prev, newOption.id]);
      setNewOptionLabel('');
      setIsCreatingMode(false);
    } catch {
      // Parent may throw; leave create mode unchanged
    }
  }, [newOptionLabel, onAddOption]);

  const onItemPress = (id: T) => () => {
    setNewSelectedItems(prev =>
      prev.includes(id) ? prev.filter(item => item !== id) : [...prev, id],
    );
  };

  const onPressApply = () => {
    onChange?.(newSelectedItems);
    onModalClose();
  };

  const onClear = () => {
    setNewSelectedItems([]);
    setPendingAddedOptions([]);
    onChange?.([]);
  };

  const renderItem: ListRenderItem<InputApplyClearSelectOption<T>> = ({
    item,
  }) => (
    <ListRow
      onPress={onItemPress(item.id)}
      disabled={item.disabled}
      style={styles.item}>
      <Check
        checked={newSelectedItems?.includes(item.id)}
        onPress={onItemPress(item.id)}
        disabled={item.disabled}
      />
      {item.AvatarProps && <ListRow.Avatar {...item.AvatarProps} />}
      <ListRow.Title
        title={item.label}
        description={item.description}
        {...item.titleProps}
      />
      {item.children}
    </ListRow>
  );

  const Placeholder = (
    <Typography color={theme.text.neutral.lighter}>{placeholder}</Typography>
  );

  return (
    <>
      <InputCore
        label={label}
        helper={effectiveHelper}
        isSuccess={isSuccess}
        isError={isError}
        focused={focused}
        disabled={disabled}>
        <InputBox
          isSuccess={isSuccess}
          isError={isError}
          disabled={disabled}
          focused={focused}
          size={size}
          onPress={onInputPress}
          RightComponent={
            <INPUT_ICONS.down size={iconSizes.x6} color={color} />
          }>
          <View style={styles.fullFlex}>
            {itemsSelected?.length ? (
              <ScrollView
                horizontal
                bounces={false}
                showsHorizontalScrollIndicator={false}
                contentContainerStyle={styles.itemsSelected}>
                {itemsSelected.map(item => (
                  <Chip
                    key={`${item.id}`}
                    text={item.label}
                    size="sm"
                    showCloseIcon
                    onClose={onItemRemove(item.id)}
                  />
                ))}
              </ScrollView>
            ) : (
              Placeholder
            )}
          </View>
        </InputBox>
      </InputCore>
      <Dialog
        isVisible={focused}
        onClose={onModalClose}
        onGoBack={isCreatingMode ? onGoBackFromCreate : undefined}
        withBackButton={isCreatingMode}
        title={menuTitle || placeholder || label}
        wrapperType="none"
        titleNumberOfLines={modalTitleNumberOfLines}
        index={isCreatingMode ? 0 : filterable && !enableDynamicSizing ? 1 : 0}
        enableDynamicSizing={enableDynamicSizing && !isCreatingMode}
        snapPoints={
          isCreatingMode
            ? CREATE_MODE_SNAP_POINTS
            : enableDynamicSizing
            ? undefined
            : snapPoints || DEFAULT_SNAP_POINTS
        }
        footer={{
          primaryButton: isCreatingMode
            ? {
                text: t('general.save'),
                onPress: onPressAddNewOption,
              }
            : {
                text: t('general.apply'),
                onPress: onPressApply,
              },
          secondaryButton: !isCreatingMode
            ? {
                text: t('general.clear'),
                onPress: onClear,
              }
            : undefined,
        }}>
        {isCreatingMode ? (
          <View style={styles.createInputContainer}>
            <InputClassic
              ref={createInputRef}
              placeholder={createInputPlaceholder ?? t('general.write_here')}
              value={newOptionLabel}
              onChangeText={setNewOptionLabel}
              showStateIcon={false}
              useBottomSheetTextInput
              keyboardType={keyboardType}
            />
          </View>
        ) : (
          <BottomSheetFlatList
            data={effectiveOptions}
            keyExtractor={keyExtractor}
            renderItem={renderItem}
            filterRule={filterRule}
            onFilterText={onFilterText}
            filterable={filterable}
            searchPlaceholder={searchPlaceholder}
            useBottomSheetTextInput={false}
            paddingBottom={paddingBottom}
            onEndReachedThreshold={DEFAULT_THRESHOLD}
            onEndReached={onEndReached}
            ListEmptyComponent={ListEmptyComponent}
            style={styles.fullFlex}
            ListHeaderComponent={
              withCreateButton ? (
                <Button
                  text={createButtonLabel || t('general.create')}
                  variant="tertiary"
                  size="sm"
                  IconLeft={IconPlus}
                  style={styles.createButton}
                  onPress={onCreateButtonPress}
                />
              ) : null
            }
          />
        )}
      </Dialog>
    </>
  );
}

export function InputApplyClearSelectController<T = number>({
  name,
  showSuccess,
  helper,
  ...props
}: InputApplyClearSelectControllerProps<T>) {
  const inputController = useInputController({
    name,
    showSuccess,
    helperText: helper,
  });

  const onChange = (newValue: T[]) => {
    inputController.onChange(newValue);
    props.onChange?.(newValue);
  };

  return (
    <InputApplyClearSelect<T>
      {...props}
      {...inputController}
      onChange={onChange}
    />
  );
}

export type {
  InputApplyClearSelectProps,
  InputApplyClearSelectOption,
  OnChangeCallback,
};
