import React, {useMemo, useState} from 'react';
import {ListRenderItem, ScrollView, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {IconPlus} from '@tabler/icons-react-native';
import {Check} from '@components/_HuGo/Checkbox';
import {Chip} from '@components/_HuGo/Chip';
import {Menu} from '@components/_HuGo/Menu';
import {Button} from '@components/_HuGo/Button';
import {Radio} from '@components/_HuGo/RadioButton';
import {Typography} from '@components/_core/Typography';
import {ListRow} from '@components/_HuGo/List';
import {useTheme} from '@shared/theme';
import {DEFAULT_THRESHOLD} from '@shared/constants';

import {INPUT_ICONS} from '../../constants';
import {useInputController} from '../../hooks/useInputController';
import {InputCore} from '../InputCore';
import {InputBox} from '../InputBox';
import {
  InputSelectControllerProps,
  InputSelectOption,
  InputSelectProps,
  OnChangeCallback,
} from './interfaces';
import {styles} from './styles';

const DEFAULT_SNAP_POINTS = ['40%', '100%'];

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

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

export function InputSelect<T = number>({
  label,
  helper,
  isError,
  isSuccess,
  disabled,
  filterable,
  searchPlaceholder,
  options,
  enableDynamicSizing,
  onClose,
  onChange,
  multipleSelect,
  placeholder,
  value,
  createButtonLabel,
  snapPoints,
  withCreateButton,
  withDivider,
  onCreatePress,
  onEndReached,
  onFilterText,
  showRadioButtonItem,
  showAvatarInCollapsedInput = true,
  ListEmptyComponent,
  formatSelectedItem,
  size,
  modalTitleNumberOfLines,
  menuTitle,
}: InputSelectProps<T>) {
  const {t} = useTranslation();
  const {theme, iconSizes} = useTheme();
  const [focused, setFocused] = useState(false);
  const color = disabled
    ? theme.text.neutral.disabled
    : theme.text.neutral.default;
  const isSelectedArray = multipleSelect && Array.isArray(value);
  const itemsSelected = useMemo(
    () =>
      isSelectedArray
        ? options.reduce((prev, current) => {
            const index = value?.findIndex(e => e === current.id);
            if (index > -1) {
              prev[index] = current;
            }
            return prev;
          }, [] as InputSelectOption<T>[])
        : undefined,
    [isSelectedArray, options, value],
  );
  const itemSelected = useMemo(
    () => options.find(option => value === option.id),
    [options, value],
  );

  const onInputPress = () => {
    setFocused(true);
  };

  const onItemRemove = (id: T) => () => {
    if (Array.isArray(value)) {
      const newValue = value.filter(element => element !== id);
      (onChange as OnChangeCallback<T[]>)?.(newValue);
    }
  };

  const onModalClose = () => {
    setFocused(false);
    onClose?.();
  };

  const onItemPress = (id: T) => () => {
    if (isSelectedArray) {
      const newValue = value.includes(id)
        ? value.filter(item => item !== id)
        : [...value, id];
      (onChange as OnChangeCallback<T[]>)?.(newValue);
    } else {
      onModalClose();
      (onChange as OnChangeCallback<T>)?.(id);
    }
  };

  const renderItem: ListRenderItem<InputSelectOption<T>> = ({item}) => (
    <ListRow
      onPress={onItemPress(item.id)}
      disabled={item.disabled}
      style={withDivider ? styles.itemWithDivider : styles.item}>
      {isSelectedArray ? (
        <Check
          checked={value?.includes(item.id)}
          onPress={onItemPress(item.id)}
          disabled={item.disabled}
        />
      ) : showRadioButtonItem ? (
        <Radio
          checked={value === item.id}
          onPress={onItemPress(item.id)}
          disabled={item.disabled}
        />
      ) : null}
      {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={helper}
        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.valueContainer}>
            {multipleSelect ? (
              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
              )
            ) : itemSelected ? (
              <View style={styles.selectedValueRow}>
                {showAvatarInCollapsedInput && itemSelected.AvatarProps ? (
                  <ListRow.Avatar {...itemSelected.AvatarProps} />
                ) : null}
                <Typography
                  color={color}
                  numberOfLines={1}
                  style={styles.selectedValueText}>
                  {formatSelectedItem
                    ? formatSelectedItem(itemSelected)
                    : itemSelected.label}
                </Typography>
              </View>
            ) : placeholder ? (
              Placeholder
            ) : null}
          </View>
        </InputBox>
      </InputCore>
      <Menu
        data={options}
        isVisible={focused}
        keyExtractor={keyExtractor}
        renderItem={renderItem}
        filterRule={filterRule}
        onFilterText={onFilterText}
        onClose={onModalClose}
        useBottomSheetTextInput={false}
        withDivider={withDivider}
        title={menuTitle || placeholder || label}
        enableDynamicSizing={enableDynamicSizing}
        snapPoints={
          enableDynamicSizing ? undefined : snapPoints || DEFAULT_SNAP_POINTS
        }
        filterable={filterable}
        searchPlaceholder={searchPlaceholder}
        onEndReachedThreshold={DEFAULT_THRESHOLD}
        onEndReached={onEndReached}
        ListEmptyComponent={ListEmptyComponent}
        ListHeaderComponent={
          withCreateButton ? (
            <Button
              text={createButtonLabel || t('general.create')}
              variant="tertiary"
              size="sm"
              IconLeft={IconPlus}
              style={styles.createButton}
              onPress={onCreatePress}
            />
          ) : null
        }
        titleNumberOfLines={modalTitleNumberOfLines}
      />
    </>
  );
}

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

  const onChange = (value: T | T[]) => {
    inputController.onChange(value);
    if (Array.isArray(value)) {
      (props.onChange as OnChangeCallback<T[]>)?.(value);
    } else {
      (props.onChange as OnChangeCallback<T>)?.(value);
    }
  };

  return <InputSelect<T> {...props} {...inputController} onChange={onChange} />;
}

export type {
  InputSelectProps,
  InputSelectOption,
  OnChangeCallback,
  InputSelectControllerProps,
};
