import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {BottomSheetModal} from '@gorhom/bottom-sheet';
import {Typography} from '@components/_core/Typography';
import {
  MentionBottomSheetFlatList,
  MentionSuggestionUserItemData,
} from '@components/_custom/MentionBottomSheetFlatList';
import {Spinner} from '@components/_HuGo/Spinner';
import {
  FIRST_SNAP_VISIBLE_ITEMS,
  LIST_BOTTOM_PADDING,
  LIST_ITEM_HEIGHT,
  SECOND_SNAP_VISIBLE_ITEMS,
} from '@components/_custom/NewPost';
import {useDebounce} from '@hooks/useDebounce';
import {useGetUsersPublic} from '@hooks/useGetUsersPublic';
import {TaggableUser, TaggedUser} from '@interfaces/taggedUsers';
import {useGetMembers} from '@modules/group/screens/GroupDetail/hooks/useGetMembers';
import {REDUCED_LIMIT} from '@services/constants';
import {SPACING, useTheme} from '@shared/theme';
import {
  getCompleteName,
  getTaggableUserId,
  isGroupTaggableUser,
  isIos,
} from '@shared/utils';

import {styles as tagComposerStyles} from '../Tag/styles';
import {styles} from './styles';

const SEARCH_DEBOUNCE_MS = 300;
const FALLBACK_COMPOSER_BOTTOM_INSET = SPACING.x7 * 4;

export interface Props {
  groupId?: number;
  taggedUsers: TaggedUser[];
  composerBottomInset: number;
  userSearch: string;
  tagUser: boolean;
  isComposerFocused: boolean;
  onPickTaggableUser: (user: TaggableUser) => void;
}

export function MentionSuggestions({
  groupId,
  taggedUsers,
  composerBottomInset,
  userSearch,
  tagUser,
  isComposerFocused,
  onPickTaggableUser,
}: Props) {
  const {t} = useTranslation();
  const {theme} = useTheme();
  const bottomSheetRef = useRef<BottomSheetModal>(null);
  const dismissedQueryRef = useRef<string | undefined>(undefined);

  const debouncedSearch = useDebounce(userSearch, SEARCH_DEBOUNCE_MS);
  const isGroupSearch = !!groupId;

  const {data: usersPublic = [], isLoading: isLoadingUsers} = useGetUsersPublic(
    {
      search: debouncedSearch,
      enabled: !isGroupSearch,
      limit: REDUCED_LIMIT,
      status: 'ACTIVE,UNCLAIMED',
    },
  );
  const {data: groupMembers, isLoading: isLoadingMembers} = useGetMembers({
    groupId: groupId!,
    search: debouncedSearch,
    enabled: isGroupSearch,
    limit: REDUCED_LIMIT,
  });

  const usersCanBeTagged = useMemo(() => {
    const users: TaggableUser[] = groupId ? groupMembers : usersPublic;
    return taggedUsers?.length
      ? users.filter(
          (user: TaggableUser) =>
            !taggedUsers.some(
              (tagged: TaggedUser) =>
                tagged.type.user.id === getTaggableUserId(user),
            ),
        )
      : users;
  }, [groupId, groupMembers, taggedUsers, usersPublic]);

  const members = useMemo<MentionSuggestionUserItemData[]>(
    () =>
      usersCanBeTagged.map((item: TaggableUser) => {
        const user = isGroupTaggableUser(item) ? item.user : item;
        return {
          id: getTaggableUserId(item),
          title: getCompleteName(user),
          profilePicture: user.profilePicture,
          pillLabel: item.isExternal ? t('group.external') : undefined,
        };
      }),
    [t, usersCanBeTagged],
  );

  const isLoadingCurrentSource = groupId ? isLoadingMembers : isLoadingUsers;
  const isLoadingSuggestions = isLoadingCurrentSource && tagUser;

  const mentionKeyExtractor = useCallback(
    (item: MentionSuggestionUserItemData) => item.id.toString(),
    [],
  );

  const getItemLayout = useCallback(
    (_data: unknown, index: number) => ({
      length: LIST_ITEM_HEIGHT,
      offset: LIST_ITEM_HEIGHT * index,
      index,
    }),
    [],
  );

  const snapPoints = useMemo(() => {
    if (!members.length) {
      return [LIST_ITEM_HEIGHT * 2 + LIST_BOTTOM_PADDING];
    }

    const firstItems = Math.min(members.length, FIRST_SNAP_VISIBLE_ITEMS);
    const firstSnapPoint = firstItems * LIST_ITEM_HEIGHT + LIST_BOTTOM_PADDING;
    const secondItems = Math.min(members.length, SECOND_SNAP_VISIBLE_ITEMS);
    const secondSnapPoint =
      secondItems * LIST_ITEM_HEIGHT + LIST_BOTTOM_PADDING;
    return firstSnapPoint === secondSnapPoint
      ? [firstSnapPoint]
      : [firstSnapPoint, secondSnapPoint + (isIos ? 0 : 6)];
  }, [members.length]);

  const shouldOpenSuggestions = isComposerFocused && tagUser;
  const hasDismissedCurrentQuery =
    tagUser && dismissedQueryRef.current === userSearch;
  const shouldShowSheet = shouldOpenSuggestions && !hasDismissedCurrentQuery;

  const onDismissSheet = useCallback(() => {
    if (tagUser && isComposerFocused) {
      dismissedQueryRef.current = userSearch;
    }
  }, [tagUser, isComposerFocused, userSearch]);

  useEffect(() => {
    if (shouldShowSheet) {
      bottomSheetRef.current?.present();
    } else {
      bottomSheetRef.current?.close();
    }
  }, [shouldShowSheet]);

  useEffect(() => {
    dismissedQueryRef.current = undefined;
  }, [userSearch]);

  useEffect(() => {
    if (tagUser) {
      dismissedQueryRef.current = undefined;
    }
  }, [tagUser]);

  const sheetBottomInset = useMemo(
    () =>
      composerBottomInset > 0
        ? composerBottomInset
        : FALLBACK_COMPOSER_BOTTOM_INSET,
    [composerBottomInset],
  );

  const onItemPress = useCallback(
    (item: MentionSuggestionUserItemData) => {
      const match = usersCanBeTagged.find(
        u => getTaggableUserId(u).toString() === item.id.toString(),
      );
      if (match) {
        onPickTaggableUser(match);
      }
    },
    [onPickTaggableUser, usersCanBeTagged],
  );

  return (
    <BottomSheetModal
      ref={bottomSheetRef}
      name="add-comment-tag-suggestions"
      bottomInset={sheetBottomInset}
      snapPoints={snapPoints}
      enableDynamicSizing={!isIos}
      accessible={!isIos}
      enablePanDownToClose
      enableOverDrag={false}
      keyboardBehavior="interactive"
      keyboardBlurBehavior="restore"
      onDismiss={onDismissSheet}
      backgroundStyle={{backgroundColor: theme.background.elements.default}}
      style={[
        styles.sheetTopShadow,
        {
          shadowColor: theme.shadow['8dp'],
          borderColor: theme.shadow['8dp'],
        },
      ]}>
      {isLoadingSuggestions ? (
        <View style={styles.loaderContainer}>
          <Spinner />
        </View>
      ) : !members.length ? (
        <View style={styles.emptyContainer}>
          <Typography weight="semiBold">{t('general.no_results')}</Typography>
        </View>
      ) : (
        <MentionBottomSheetFlatList
          data={members}
          keyExtractor={mentionKeyExtractor}
          getItemLayout={getItemLayout}
          pageSize={members.length}
          onItemPress={onItemPress}
          listItemStyle={[
            tagComposerStyles.listItem,
            {backgroundColor: theme.background.elements.default},
          ]}
          contentContainerStyle={{
            backgroundColor: theme.background.elements.default,
            paddingBottom: LIST_BOTTOM_PADDING,
          }}
          isAccessible={!isIos}
        />
      )}
    </BottomSheetModal>
  );
}
