import {useFocusEffect, useNavigation} from '@react-navigation/native';
import React, {useCallback, useEffect, useState, useRef} from 'react';
import {
  FlatList,
  RefreshControl,
  StatusBar,
  StyleSheet,
  ViewToken,
} from 'react-native';

import Animated from 'react-native-reanimated';
import {useDispatch, useSelector, useStore} from 'react-redux';
import {TabsGradient, TaggLoadingIndicator, Background} from '../../components';
import {SP_PAGE_SIZE} from '../../constants';
import SuggestedPeopleOnboardingStackScreen from '../../routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen';
import {getSuggestedPeople} from '../../services/SuggestedPeopleService';
import {cancelFriendRequest, resetScreenType} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {
  FriendshipStatusType,
  ProfilePreviewType,
  ScreenType,
  SuggestedPeopleDataType,
  BackgroundGradientType,
} from '../../types';
import {
  fetchUserX,
  getUserAsProfilePreviewType,
  handleAddFriend,
  normalize,
  SCREEN_HEIGHT,
  SCREEN_WIDTH,
} from '../../utils';
import {userXInStore} from './../../utils/';
import SPBody from './SPBody';
/**
 * Bare bones for suggested people consisting of:
 * * Image, title, name, username, add friend button [w/o functionality]
 */

const SuggestedPeopleScreen: React.FC = () => {
  const y = Animated.useValue(0);
  const navigation = useNavigation();
  const state: RootState = useStore().getState();
  const dispatch = useDispatch();
  const screenType = ScreenType.SuggestedPeople;
  const {suggested_people_linked} = useSelector(
    (state: RootState) => state.user.profile,
  ) ?? {suggested_people_linked: -1};
  const {userId: loggedInUserId} = useSelector(
    (state: RootState) => state.user.user,
  );
  const {suggestedPeopleImage} = useSelector((state: RootState) => state.user);
  const [people, setPeople] = useState<SuggestedPeopleDataType[]>([]);
  const [displayedUser, setDisplayedUser] = useState<SuggestedPeopleDataType>();
  const [page, setPage] = useState(0);
  const [refreshing, setRefreshing] = useState(false);
  const [shouldResetData, setShouldResetData] = useState(false);
  const [hideStatusBar, setHideStatusBar] = useState(false);
  // boolean for showing/hiding loading indicator
  const [loading, setLoading] = useState(true);

  // set loading to false once there are people to display
  useEffect(() => {
    people.length ? setLoading(false) : setLoading(true);
  }, [people]);

  const stausBarRef = useRef(hideStatusBar);

  // loads data and append it to users based on current page
  useEffect(() => {
    loadMore();
  }, [page]);

  useEffect(() => {
    if (shouldResetData) {
      if (page !== 0) {
        setPage(0);
      } else {
        loadMore();
      }
    }
  }, [shouldResetData]);

  useEffect(() => {
    const appendSelf = async () => {
      const self = {
        user: getUserAsProfilePreviewType(state.user.user, state.user.profile),
        mutual_friends: [],
        badges: [],
        social_links: [],
        suggested_people_url: suggestedPeopleImage,
      };
      people.unshift(self);
      setPeople(people);
    };
    if (suggested_people_linked < 2) {
      if (people.length > 1 && people[0].user.id !== loggedInUserId) {
        appendSelf();
      }
    }
  }, [suggestedPeopleImage]);

  const loadMore = async () => {
    const loadNextPage = async () =>
      await getSuggestedPeople(
        SP_PAGE_SIZE,
        shouldResetData ? 0 : page * SP_PAGE_SIZE,
      );

    loadNextPage().then((newUsers) => {
      loadUserDataToStore(newUsers.map((ppl) => ppl.user));
      if (shouldResetData) {
        setPeople([]);
      }
      setPeople(shouldResetData ? newUsers : people.concat(newUsers));
      setShouldResetData(false);
    });
  };

  const loadUserDataToStore = async (users: ProfilePreviewType[]) => {
    const loadUserData = async (user: ProfilePreviewType) => {
      if (!userXInStore(state, screenType, user.id)) {
        await fetchUserX(
          dispatch,
          {userId: user.id, username: user.username},
          screenType,
        );
      }
    };
    await Promise.all(users.map((user) => loadUserData(user)));
  };

  const onRefresh = () => {
    const reset = async () => {
      await dispatch(resetScreenType(screenType));
      setShouldResetData(true);
    };
    setRefreshing(true);
    reset().then(() => {
      setRefreshing(false);
    });
  };

  useFocusEffect(
    useCallback(() => {
      const navigateToAnimatedTutorial = () => {
        // if the user has finished the previous SP onboarding
        if (suggested_people_linked === 1) {
          navigation.navigate('AnimatedTutorial');
        }
      };
      navigateToAnimatedTutorial();
      StatusBar.setHidden(stausBarRef.current);
      StatusBar.setBarStyle('light-content');
      return () => {
        StatusBar.setHidden(false);
        StatusBar.setBarStyle('dark-content');
      };
    }, [navigation, suggested_people_linked]),
  );

  const updateDisplayedUser = async (
    user: ProfilePreviewType,
    status: FriendshipStatusType,
    requester_id: string,
  ) => {
    const localDisplayedUser: SuggestedPeopleDataType = {
      ...displayedUser,
      friendship: {status, requester_id},
    };
    setDisplayedUser(localDisplayedUser);

    setPeople(
      people.map((item) => {
        if (item.user.id === user.id) {
          item.friendship.status = status;
          item.friendship.requester_id = requester_id;
        }
        return item;
      }),
    );
  };

  const onAddFriend = async (user: ProfilePreviewType) => {
    handleAddFriend(screenType, user, dispatch, state);
    updateDisplayedUser(user, 'requested', loggedInUserId);
  };

  const onCancelRequest = (user: ProfilePreviewType) => {
    dispatch(cancelFriendRequest(user.id));
    updateDisplayedUser(user, 'no_record', '');
  };

  const onViewableItemsChanged = useCallback(
    ({viewableItems}: {viewableItems: ViewToken[]}) => {
      setHideStatusBar(viewableItems[0].index !== 0);
      stausBarRef.current = viewableItems[0].index !== 0;
    },
    [],
  );

  return suggested_people_linked === 0 ? (
    <SuggestedPeopleOnboardingStackScreen />
  ) : loading ? (
    <>
      <TaggLoadingIndicator fullscreen />
      <Background gradientType={BackgroundGradientType.Dark} />
    </>
  ) : (
    <>
      <FlatList
        data={people}
        renderItem={(item) => {
          return (
            <SPBody
              itemIndex={item.index}
              item={item.item}
              onAddFriend={onAddFriend}
              onCancelRequest={onCancelRequest}
              loggedInUserId={loggedInUserId}
            />
          );
        }}
        keyExtractor={(item, index) => index.toString()}
        showsVerticalScrollIndicator={false}
        onViewableItemsChanged={onViewableItemsChanged}
        onEndReached={() => setPage(page + 1)}
        refreshControl={
          <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
        }
        pagingEnabled
      />
      <TabsGradient />
    </>
  );
};

const styles = StyleSheet.create({
  mainContainer: {
    flexDirection: 'column',
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    paddingVertical: '15%',
    paddingBottom: '20%',
    justifyContent: 'space-between',
    alignSelf: 'center',
  },
  marginManager: {marginHorizontal: '5%'},
  image: {
    position: 'absolute',
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    zIndex: 0,
  },
  title: {
    zIndex: 1,
    paddingTop: '3%',
    alignSelf: 'center',
    fontSize: normalize(22),
    lineHeight: normalize(26),
    fontWeight: '800',
    letterSpacing: normalize(3),
    color: '#FFFEFE',
    textShadowColor: 'rgba(0, 0, 0, 0.4)',
    textShadowOffset: {width: normalize(2), height: normalize(2)},
    textShadowRadius: normalize(2),
  },
  firstName: {
    color: '#fff',
    fontWeight: '800',
    fontSize: normalize(24),
    lineHeight: normalize(29),
    textShadowColor: 'rgba(0, 0, 0, 0.3)',
    textShadowOffset: {width: normalize(2), height: normalize(2)},
    textShadowRadius: normalize(2),
    letterSpacing: normalize(2.5),
    alignSelf: 'baseline',
  },
  username: {
    color: '#fff',
    fontWeight: '600',
    fontSize: normalize(15),
    lineHeight: normalize(18),
    textShadowColor: 'rgba(0, 0, 0, 0.3)',
    textShadowOffset: {width: normalize(2), height: normalize(2)},
    textShadowRadius: normalize(2),
    letterSpacing: normalize(2),
  },
  nameInfoContainer: {},
  addButton: {
    justifyContent: 'center',
    alignItems: 'center',
    width: SCREEN_WIDTH * 0.3,
    height: SCREEN_WIDTH * 0.085,
    padding: 0,
    borderWidth: 2,
    borderColor: '#fff',
    borderRadius: 1,
    marginLeft: '1%',
    marginTop: '4%',
    shadowColor: 'rgb(0, 0, 0)',
    shadowRadius: 2,
    shadowOffset: {width: 2, height: 2},
    shadowOpacity: 0.5,
  },
  addButtonTitle: {
    color: 'white',
    padding: 0,
    fontSize: normalize(15),
    lineHeight: normalize(18),
    fontWeight: 'bold',
    textAlign: 'center',
    letterSpacing: normalize(1),
  },
  addUserContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'flex-start',
    marginBottom: '5%',
  },
  requestedButton: {
    justifyContent: 'center',
    alignItems: 'center',
    width: SCREEN_WIDTH * 0.3,
    height: SCREEN_WIDTH * 0.085,
    padding: 0,
    borderWidth: 2,
    borderColor: 'transparent',
    borderRadius: 1,
    marginLeft: '1%',
    marginTop: '4%',
    shadowColor: 'rgb(0, 0, 0)',
    shadowRadius: 2,
    shadowOffset: {width: 2, height: 2},
    shadowOpacity: 0.5,
  },
  requestedButtonTitle: {
    backgroundColor: 'transparent',
    fontSize: normalize(15),
    lineHeight: normalize(18),
    fontWeight: 'bold',
    textAlign: 'center',
    letterSpacing: normalize(1),
  },
  body: {},

  button: {
    justifyContent: 'center',
    alignItems: 'center',
    width: SCREEN_WIDTH * 0.4,
    aspectRatio: 154 / 33,
    borderWidth: 2,
    borderColor: '#fff',
    borderRadius: 3,
    marginRight: '2%',
    marginLeft: '1%',
  },
  transparentBG: {
    backgroundColor: 'transparent',
  },
  lightBlueBG: {
    backgroundColor: '#fff',
  },
  label: {
    fontSize: normalize(15),
    fontWeight: '700',
    letterSpacing: 1,
  },
  blueLabel: {
    color: '#fff',
  },
  whiteLabel: {
    color: 'white',
  },
});
export default SuggestedPeopleScreen;
