import AsyncStorage from '@react-native-community/async-storage';
import {useFocusEffect} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
import {Keyboard, ScrollView, StatusBar, StyleSheet} from 'react-native';
import Animated, {Easing, timing} from 'react-native-reanimated';
import {SafeAreaView} from 'react-native-safe-area-context';
import {useDispatch, useSelector} from 'react-redux';
import {
  RecentSearches,
  SearchBar,
  SearchCategories,
  SearchResultList,
  SearchResultsBackground,
  TabsGradient,
} from '../../components';
import {SEARCH_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants';
import {loadSearchResults} from '../../services';
import {resetScreenType} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {
  CategoryPreviewType,
  ProfilePreviewType,
  ScreenType,
  SearchCategoryType,
} from '../../types';
import {
  getRecentlySearchedCategories,
  getRecentlySearchedUsers,
  normalize,
  SCREEN_HEIGHT,
  SCREEN_WIDTH,
} from '../../utils';

/**
 * Search Screen for user recommendations and a search
 * tool to allow user to find other users
 */

const SearchScreen: React.FC = () => {
  const {recentSearches} = useSelector((state: RootState) => state.taggUsers);
  const {
    profile: {university = ''},
  } = useSelector((state: RootState) => state.user);
  const [query, setQuery] = useState<string>('');
  const [results, setResults] = useState<Array<any> | undefined>(undefined);
  const [recents, setRecents] = useState<Array<ProfilePreviewType>>(
    recentSearches ?? [],
  );
  const [recentCategories, setRecentCategories] = useState<
    CategoryPreviewType[]
  >([]);
  const [searching, setSearching] = useState(false);
  const top = Animated.useValue(-SCREEN_HEIGHT);
  const defaultButtons: SearchCategoryType[] = [21, 22, 23, 24].map((year) => ({
    id: -1,
    name: `${university.split(' ')[0]} '${year}`,
    category: university,
  }));
  const [keyboardVisible, setKeyboardVisible] = React.useState(
    'keyboardVisible',
  );
  useEffect(() => {
    const showKeyboard = () => setKeyboardVisible('keyboardVisibleTrue');
    Keyboard.addListener('keyboardWillShow', showKeyboard);
    return () => Keyboard.removeListener('keyboardWillShow', showKeyboard);
  }, []);

  useEffect(() => {
    const hideKeyboard = () => setKeyboardVisible('keyboardVisibleFalse');
    Keyboard.addListener('keyboardWillHide', hideKeyboard);
    return () => Keyboard.removeListener('keyboardWillHide', hideKeyboard);
  }, []);
  const dispatch = useDispatch();

  /*
   * Main handler for changes in query.
   */
  useEffect(() => {
    if (!searching) {
      return;
    }
    if (query.length < 3) {
      loadRecentlySearched().then(() => setResults(undefined));
      return;
    }
    (async () => {
      const searchResults = await loadSearchResults(
        `${SEARCH_ENDPOINT}?query=${query}`,
      );
      if (query.length > 2) {
        const sanitizedResult = [
          {
            title: 'badges',
            data: searchResults?.badges,
          },
          {
            title: 'categories',
            data: searchResults?.categories,
          },
          {
            title: 'users',
            data: searchResults?.users,
          },
        ];
        setResults(sanitizedResult);
      } else {
        setResults(undefined);
      }
    })();
  }, [query]);

  /**
   * Code under useFocusEffect gets executed every time the screen comes under focus / is being viewed by the user.
   * This is done to reset the users stored in our store for the Search screen.
   * Read more here : https://reactnavigation.org/docs/function-after-focusing-screen/
   */
  useFocusEffect(() => {
    dispatch(resetScreenType(ScreenType.Search));
  });

  // when searching state changes, run animation and reset query accordingly
  useEffect(() => {
    if (searching) {
      loadRecentlySearched().then(() => {
        timing(top, topInConfig).start();
      });
    } else {
      setQuery('');
      handleBlur();
      timing(top, topOutConfig).start(() => setResults(undefined));
    }
  }, [searching]);

  // loads recent searches (users & categories) from AsyncStorage
  const loadRecentlySearched = async () => {
    return Promise.all([
      getRecentlySearchedUsers(),
      getRecentlySearchedCategories(),
    ]).then(
      ([users, categories]: [ProfilePreviewType[], CategoryPreviewType[]]) => {
        setRecents(users);
        setRecentCategories(categories);
      },
    );
  };
  const clearRecentlySearched = async () => {
    try {
      AsyncStorage.removeItem('@recently_searched_users');
      AsyncStorage.removeItem('@recently_searched_categories');
      loadRecentlySearched();
    } catch (e) {
      console.log(e);
    }
  };

  const topInConfig = {
    duration: 180,
    toValue: 0,
    easing: Easing.bezier(0.31, 0.14, 0.66, 0.82),
  };
  const topOutConfig = {
    duration: 180,
    toValue: -SCREEN_HEIGHT,
    easing: Easing.inOut(Easing.ease),
  };
  const handleFocus = () => {
    setSearching(true);
  };
  const handleBlur = () => {
    Keyboard.dismiss();
  };
  const handleCancel = () => {
    setSearching(false);
  };

  return (
    <SafeAreaView style={styles.screenContainer}>
      <StatusBar barStyle="dark-content" />
      <SearchBar
        onCancel={handleCancel}
        onChangeText={setQuery}
        onBlur={handleBlur}
        onFocus={handleFocus}
        value={query}
        {...{top, searching}}
      />
      <ScrollView
        scrollEnabled={!searching}
        keyboardShouldPersistTaps={'always'}
        stickyHeaderIndices={[4]}
        contentContainerStyle={styles.contentContainer}
        showsVerticalScrollIndicator={false}>
        <SearchCategories defaultButtons={defaultButtons} />
        <SearchResultsBackground {...{top}}>
          {results === undefined &&
          recents.length + recentCategories.length !== 0 ? (
            <RecentSearches
              sectionTitle="Recent"
              onPress={clearRecentlySearched}
              screenType={ScreenType.Search}
              {...{recents, recentCategories}}
            />
          ) : (
            <SearchResultList
              {...{results}}
              keyboardVisible={keyboardVisible === 'keyboardVisibleTrue'}
              previewType={'Search'}
              screenType={ScreenType.Search}
            />
          )}
        </SearchResultsBackground>
      </ScrollView>
      <TabsGradient />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  screenContainer: {
    paddingTop: 15,
    backgroundColor: '#fff',
  },
  contentContainer: {
    height: SCREEN_HEIGHT,
    paddingTop: '2%',
    paddingBottom: SCREEN_HEIGHT / 3,
    paddingHorizontal: '3%',
  },
  header: {
    marginVertical: 20,
    zIndex: 1,
  },
  recentsHeaderContainer: {
    flexDirection: 'row',
  },
  recentsHeader: {
    fontSize: 17,
    fontWeight: 'bold',
    flexGrow: 1,
  },
  clear: {
    fontSize: normalize(17),
    fontWeight: 'bold',
    color: TAGG_LIGHT_BLUE,
  },
  image: {
    width: SCREEN_WIDTH,
    height: SCREEN_WIDTH,
  },
  textContainer: {
    marginTop: '10%',
  },
  headerText: {
    color: '#fff',
    fontSize: normalize(32),
    fontWeight: '600',
    textAlign: 'center',
    marginBottom: '4%',
    marginHorizontal: '10%',
  },
  subtext: {
    color: '#fff',
    fontSize: normalize(16),
    fontWeight: '600',
    textAlign: 'center',
    marginHorizontal: '10%',
  },
  cancelButton: {
    position: 'absolute',
    height: '100%',
    justifyContent: 'center',
    paddingHorizontal: 5,
  },
  cancelText: {
    color: '#818181',
    fontWeight: '600',
  },
});
export default SearchScreen;
