import React, { useCallback, useMemo } from 'react';
import { StyleSheet } from 'react-native';

import { FlatList } from 'react-native-gesture-handler';

import Animated, { LinearTransition, ZoomIn, ZoomOut } from 'react-native-reanimated';

import { SearchSourceState, TextComposerState, TextComposerSuggestion } from 'stream-chat';

import { useA11yLabel } from '../../a11y/hooks/useA11yLabel';
import { useAnnounceOnShow } from '../../a11y/hooks/useAnnounceOnShow';
import { useComponentsContext } from '../../contexts/componentsContext/ComponentsContext';
import { useMessageComposer } from '../../contexts/messageInputContext/hooks/useMessageComposer';
import { useTheme } from '../../contexts/themeContext/ThemeContext';
import { useStableCallback } from '../../hooks';
import { useStateStore } from '../../hooks/useStateStore';
import { primitives } from '../../theme';
import { ClippingFadeBottom } from '../UIComponents/ClippingFadeBottom';

export const DEFAULT_LIST_HEIGHT = 240;

export type AutoCompleteSuggestionListProps = Record<string, never>;

const textComposerStateSelector = (state: TextComposerState) => ({
  suggestions: state.suggestions,
  text: state.text,
});

const searchSourceStateSelector = (nextValue: SearchSourceState) => ({
  items: nextValue.items,
});

export const AutoCompleteSuggestionList = () => {
  const { AutoCompleteSuggestionHeader, AutoCompleteSuggestionItem } = useComponentsContext();

  const messageComposer = useMessageComposer();
  const { textComposer } = messageComposer;
  const { suggestions } = useStateStore(textComposer.state, textComposerStateSelector);
  const { items } = useStateStore(suggestions?.searchSource.state, searchSourceStateSelector) ?? {};
  const trigger = suggestions?.trigger;
  const queryText = suggestions?.query;

  const triggerType = {
    '/': 'command',
    ':': 'emoji',
    '@': 'mention',
  }[trigger ?? ''];

  const showList = useMemo(() => {
    return items && items?.length > 0;
  }, [items]);

  const {
    theme: {
      semantics,
      messageComposer: {
        container: { maxHeight },
      },
    },
  } = useTheme();
  const styles = useStyles();

  const renderItem = useCallback(
    ({ item }: { item: TextComposerSuggestion }) => {
      return AutoCompleteSuggestionItem ? (
        <AutoCompleteSuggestionItem itemProps={item} triggerType={triggerType} />
      ) : null;
    },
    [AutoCompleteSuggestionItem, triggerType],
  );

  const renderHeader = useCallback(() => {
    return AutoCompleteSuggestionHeader ? (
      <AutoCompleteSuggestionHeader queryText={queryText} triggerType={triggerType} />
    ) : null;
  }, [AutoCompleteSuggestionHeader, queryText, triggerType]);

  const loadMore = useStableCallback(() => suggestions?.searchSource.search());

  // Polite announcement when the suggestion list appears. Different label per
  // trigger type so the user knows whether they're looking at mentions,
  // commands, or emoji without having to swipe in to find out.
  const announceLabelKey =
    triggerType === 'command'
      ? 'a11y/Command suggestions available'
      : triggerType === 'emoji'
        ? 'a11y/Emoji suggestions available'
        : 'a11y/Mention suggestions available';
  const announceLabel = useA11yLabel(announceLabelKey);
  useAnnounceOnShow(!!(showList && triggerType), announceLabel);

  if (!showList || !triggerType) {
    return null;
  }

  return (
    <Animated.View
      accessibilityRole='menu'
      entering={ZoomIn.duration(200)}
      exiting={ZoomOut.duration(200)}
      layout={LinearTransition.duration(200)}
      style={styles.container}
    >
      <FlatList
        data={items}
        keyboardShouldPersistTaps='always'
        keyExtractor={(item) => item.id}
        ListHeaderComponent={renderHeader}
        onEndReached={loadMore}
        onEndReachedThreshold={0.1}
        renderItem={renderItem}
        style={[styles.flatlist, { maxHeight }]}
        contentContainerStyle={styles.flatlistContentContainer}
        testID={'auto-complete-suggestion-list'}
      />
      <ClippingFadeBottom backgroundColor={String(semantics.backgroundCoreElevation1)} />
    </Animated.View>
  );
};

const useStyles = () => {
  const {
    theme: {
      semantics,
      messageComposer: {
        suggestionsListContainer: { flatlist, flatlistContentContainer },
      },
    },
  } = useTheme();
  return useMemo(
    () =>
      StyleSheet.create({
        container: {
          maxHeight: DEFAULT_LIST_HEIGHT,
          backgroundColor: semantics.backgroundCoreElevation1,
          borderTopWidth: 1,
          borderColor: semantics.borderCoreDefault,
        },
        flatlistContentContainer: {
          paddingVertical: primitives.spacingXs,
          backgroundColor: 'transparent',
          ...flatlistContentContainer,
        },
        flatlist: {
          backgroundColor: semantics.backgroundCoreElevation1,
          shadowColor: semantics.textOnAccent,
          borderRadius: 8,
          elevation: 3,
          marginHorizontal: 8,
          shadowOffset: {
            height: 1,
            width: 0,
          },
          shadowOpacity: 0.22,
          shadowRadius: 2.22,
          ...flatlist,
        },
      }),
    [semantics, flatlist, flatlistContentContainer],
  );
};

AutoCompleteSuggestionList.displayName =
  'AutoCompleteSuggestionList{messageComposer{suggestions{List}}}';
