import React, { useCallback, useRef, useState } from 'react';
import {
  BackHandler,
  NativeScrollEvent,
  NativeSyntheticEvent,
  StyleSheet,
  View,
  useWindowDimensions,
} from 'react-native';
import { useQuery } from '@realm/react';
import { useTheme } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
import { FlashList } from '@shopify/flash-list';
import {
  ParamListBase,
  useFocusEffect,
  useNavigation,
} from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { ROUTE, SORT_DIRECTION, memesSortQuery } from '../types';
import { RootState, setNavVisible } from '../state';
import { Meme } from '../database';
import { HideableHeader, MemesHeader, MemesList } from '../components';
import { useDeviceOrientation } from '@react-native-community/hooks';

const memesStyles = StyleSheet.create({
  listView: {
    paddingHorizontal: '4%',
    width: '100%',
    height: '100%',
  },
});

const Memes = () => {
  const { colors } = useTheme();
  const { navigate } =
    useNavigation<NativeStackNavigationProp<ParamListBase>>();
  const { height } = useWindowDimensions();
  const orientation = useDeviceOrientation();
  const sort = useSelector((state: RootState) => state.memes.sort);
  const sortDirection = useSelector(
    (state: RootState) => state.memes.sortDirection,
  );
  const favoritesOnly = useSelector(
    (state: RootState) => state.memes.favoritesOnly,
  );
  const filter = useSelector((state: RootState) => state.memes.filter);
  const navVisisble = useSelector(
    (state: RootState) => state.navigation.navVisible,
  );
  const autoFocus = useSelector(
    (state: RootState) => state.settings.autoFocusMemesSearch,
  );
  const dispatch = useDispatch();

  const [flashListPadding, setFlashListPadding] = useState(0);
  const [search, setSearch] = useState('');

  const memes = useQuery<Meme>(
    Meme.schema.name,
    collectionIn => {
      let collection = collectionIn;

      const tokens = search
        .match(/"[^"]+"|\S+/gi)
        ?.map(token => token.replaceAll(/["']/g, ''));

      const tags = tokens
        ?.filter(token => token.startsWith('#'))
        .map(tag => tag.slice(1));

      const words = tokens?.filter(token => !token.startsWith('#'));

      const tagsQuery = tags
        ?.map((tag, index) => `ANY tags.name CONTAINS[c] $${index}`)
        .join(' OR ');

      const wordsQuery = words
        ?.map((word, index) => `title CONTAINS[c] $${index}`)
        .join(' OR ');

      if (favoritesOnly) collection = collection.filtered('isFavorite == true');
      if (filter) collection = collection.filtered('memeType == $0', filter);
      if (tags && tagsQuery) {
        collection = collection.filtered(tagsQuery, ...tags);
      }
      if (words && wordsQuery) {
        collection = collection.filtered(wordsQuery, ...words);
      }

      collection = collection.sorted(
        memesSortQuery(sort),
        sortDirection === SORT_DIRECTION.DESCENDING,
      );

      return collection;
    },
    [sort, sortDirection, favoritesOnly, filter, search],
  );

  const previousOffset = useRef(0);

  const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
    const currentOffset = event.nativeEvent.contentOffset.y;

    if (currentOffset <= 150) {
      dispatch(setNavVisible(true));
    } else {
      const diff = currentOffset - previousOffset.current;
      if (Math.abs(diff) > 35) {
        dispatch(setNavVisible(diff < 0));
      }
    }

    previousOffset.current = currentOffset;
  };

  const flashListRef = useRef<FlashList<Meme>>(null);

  useFocusEffect(
    useCallback(() => {
      const handleBackPress = () => {
        if (previousOffset.current <= 0) return false;
        flashListRef.current?.scrollToOffset({ offset: 0, animated: true });
        return true;
      };

      BackHandler.addEventListener('hardwareBackPress', handleBackPress);

      return () =>
        BackHandler.removeEventListener('hardwareBackPress', handleBackPress);
    }, []),
  );

  useFocusEffect(
    useCallback(() => {
      dispatch(setNavVisible(true));
    }, [dispatch]),
  );

  return (
    <>
      <HideableHeader visible={navVisisble}>
        <MemesHeader
          search={search}
          setSearch={setSearch}
          autoFocus={autoFocus}
          onLayout={event => {
            setFlashListPadding(
              event.nativeEvent.layout.height +
                height * (orientation === 'portrait' ? 0.02 : 0.04),
            );
          }}
        />
      </HideableHeader>
      <View
        style={[memesStyles.listView, { backgroundColor: colors.background }]}>
        <MemesList
          memes={memes}
          flashListRef={flashListRef}
          flashListPadding={flashListPadding}
          handleScroll={handleScroll}
          focusMeme={(index: number) => {
            navigate(ROUTE.MEME_VIEW, {
              ids: memes.map(meme => meme.id.toHexString()),
              index,
            });
          }}
        />
      </View>
    </>
  );
};

export default Memes;
