import {useFocusEffect, useNavigation} from '@react-navigation/native';
import React, {useCallback, useEffect, useState} from 'react';
import {
  Alert,
  LayoutChangeEvent,
  NativeScrollEvent,
  NativeSyntheticEvent,
  RefreshControl,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
import {useDispatch, useSelector, useStore} from 'react-redux';
import Cover from './Cover';
import GreyPlusLogo from '../../assets/icons/grey-plus-logo.svg';
import {COVER_HEIGHT, TAGG_LIGHT_BLUE} from '../../constants';
import {
  UPLOAD_MOMENT_PROMPT_THREE_HEADER,
  UPLOAD_MOMENT_PROMPT_THREE_MESSAGE,
  UPLOAD_MOMENT_PROMPT_TWO_HEADER,
  UPLOAD_MOMENT_PROMPT_TWO_MESSAGE,
} from '../../constants/strings';
import {
  blockUnblockUser,
  deleteUserMomentsForCategory,
  loadFriendsData,
  updateMomentCategories,
  updateUserXFriends,
} from '../../store/actions';
import {
  EMPTY_MOMENTS_LIST,
  EMPTY_PROFILE_PREVIEW_LIST,
  NO_PROFILE,
  NO_USER,
} from '../../store/initialStates';
import {RootState} from '../../store/rootreducer';
import {CategorySelectionScreenType, MomentType, ScreenType} from '../../types';
import {
  fetchUserX,
  getUserAsProfilePreviewType,
  moveCategory,
  normalize,
  SCREEN_HEIGHT,
  userLogin,
} from '../../utils';
import {TaggPrompt} from '../common';
import {Moment} from '../moments';
import TaggsBar from '../taggs/TaggsBar';
import ProfileBody from './ProfileBody';
import ProfileCutout from './ProfileCutout';
import ProfileHeader from './ProfileHeader';

interface ContentProps {
  y: Animated.Value<number>;
  userXId: string | undefined;
  screenType: ScreenType;
}

const Content: React.FC<ContentProps> = ({y, userXId, screenType}) => {
  const dispatch = useDispatch();

  const {user = NO_USER, profile = NO_PROFILE} = userXId
    ? useSelector((state: RootState) => state.userX[screenType][userXId])
    : useSelector((state: RootState) => state.user);

  const {friends = EMPTY_PROFILE_PREVIEW_LIST} = userXId
    ? useSelector((state: RootState) => state.userX[screenType][userXId])
    : useSelector((state: RootState) => state.friends);

  const {
    friends: friendsLoggedInUser = EMPTY_PROFILE_PREVIEW_LIST,
  } = useSelector((state: RootState) => state.friends);

  const {moments = EMPTY_MOMENTS_LIST} = userXId
    ? useSelector((state: RootState) => state.userX[screenType][userXId])
    : useSelector((state: RootState) => state.moments);

  const {momentCategories = []} = userXId
    ? useSelector((state: RootState) => state.userX[screenType][userXId])
    : useSelector((state: RootState) => state.momentCategories);

  const {blockedUsers = EMPTY_PROFILE_PREVIEW_LIST} = useSelector(
    (state: RootState) => state.blocked,
  );
  const {user: loggedInUser = NO_USER} = useSelector(
    (state: RootState) => state.user,
  );
  const state = useStore().getState();

  const navigation = useNavigation();

  /**
   * States
   */
  const [imagesMap, setImagesMap] = useState<Map<string, MomentType[]>>(
    new Map(),
  );
  const [isFriend, setIsFriend] = useState<boolean>(false);
  const [isBlocked, setIsBlocked] = useState<boolean>(false);
  const [profileBodyHeight, setProfileBodyHeight] = useState(0);
  const [shouldBounce, setShouldBounce] = useState<boolean>(true);
  const [refreshing, setRefreshing] = useState<boolean>(false);

  const [isStageTwoPromptClosed, setIsStageTwoPromptClosed] = useState<boolean>(
    false,
  );
  const [isStageOnePromptClosed, setIsStageOnePromptClosed] = useState<boolean>(
    false,
  );
  const [
    isStageThreePromptClosed,
    setIsStageThreePromptClosed,
  ] = useState<boolean>(false);

  const onRefresh = useCallback(() => {
    const refrestState = async () => {
      if (!userXId) {
        await userLogin(dispatch, loggedInUser);
      } else {
        await fetchUserX(dispatch, user, screenType);
      }
    };
    setRefreshing(true);
    refrestState().then(() => {
      setRefreshing(false);
    });
  }, []);

  const onLayout = (e: LayoutChangeEvent) => {
    const {height} = e.nativeEvent.layout;
    setProfileBodyHeight(height);
  };

  const createImagesMap = useCallback(() => {
    var map = new Map();
    moments.forEach(function (imageObject) {
      var moment_category = imageObject.moment_category;
      if (map.has(moment_category)) {
        map.get(moment_category).push(imageObject);
      } else {
        map.set(moment_category, [imageObject]);
      }
    });
    setImagesMap(map);
  }, [moments]);

  useEffect(() => {
    createImagesMap();
  }, [createImagesMap]);

  const move = (direction: 'up' | 'down', title: string) => {
    let categories = [...momentCategories];
    categories = moveCategory(categories, title, direction === 'up');
    dispatch(updateMomentCategories(categories, false));
  };

  /**
   * Prompt user to perform an activity based on their profile completion stage
   * To fire 2 seconds after the screen comes in focus
   * 1 means STAGE_1:
   *    The user must upload a moment, so take them to a screen  guiding them to post a moment
   * 2 means STAGE_2:
   *    The user must create another category so show a prompt on top of the screen
   * 3 means STAGE_3:
   *    The user must upload a moment to the second category, so show a prompt on top of the screen
   * Else, profile is complete and no prompt needs to be shown
   */
  useFocusEffect(
    useCallback(() => {
      const navigateToMomentUploadPrompt = () => {
        switch (profile.profile_completion_stage) {
          case 1:
            if (
              momentCategories &&
              momentCategories[0] &&
              !isStageOnePromptClosed
            ) {
              navigation.navigate('MomentUploadPrompt', {
                screenType,
                momentCategory: momentCategories[0],
              });
              setIsStageOnePromptClosed(true);
            }
            break;
          case 2:
            setIsStageTwoPromptClosed(false);
            break;
          case 3:
            setIsStageThreePromptClosed(false);
            break;
          default:
            break;
        }
      };
      if (!userXId) {
        setTimeout(navigateToMomentUploadPrompt, 2000);
      }
    }, [
      profile.profile_completion_stage,
      momentCategories,
      userXId,
      isStageOnePromptClosed,
    ]),
  );

  useEffect(() => {
    const isActuallyBlocked = blockedUsers.some(
      (cur_user) => user.username === cur_user.username,
    );
    if (isBlocked != isActuallyBlocked) {
      setIsBlocked(isActuallyBlocked);
    }
  }, [blockedUsers, user]);

  /**
   * Handles a click on the block / unblock button.
   * loadFriends updates friends list for the logged in user
   * updateUserXFriends updates friends list for the user.
   */
  const handleBlockUnblock = async (callback?: () => void) => {
    await dispatch(
      blockUnblockUser(
        loggedInUser,
        getUserAsProfilePreviewType(user, profile),
        isBlocked,
      ),
    );
    await dispatch(loadFriendsData(loggedInUser.userId));
    await dispatch(updateUserXFriends(user.userId, state));
    if (callback) {
      callback();
    }
  };

  /**
   * Handle deletion of a category
   * Confirm with user before deleting the category
   * @param category category to be deleted
   */
  const handleCategoryDeletion = (category: string) => {
    Alert.alert(
      'Category Deletion',
      `Are you sure that you want to delete the category ${category} ?`,
      [
        {
          text: 'Cancel',
          style: 'cancel',
        },
        {
          text: 'Yes',
          onPress: () => {
            dispatch(
              updateMomentCategories(
                momentCategories.filter((mc) => mc !== category),
                false,
              ),
            );
            dispatch(deleteUserMomentsForCategory(category));
          },
        },
      ],
      {cancelable: true},
    );
  };

  const handleScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
    /**
     * Set the new y position
     */
    const newY = e.nativeEvent.contentOffset.y;
    y.setValue(newY);

    /**
     * Do not allow overflow of scroll on bottom of the screen
     * SCREEN_HEIGHT - COVER_HEIGHT = Height of the scroll view
     */
    if (newY >= SCREEN_HEIGHT - COVER_HEIGHT) {
      setShouldBounce(false);
    } else if (newY === 0) {
      setShouldBounce(true);
    }
  };

  return (
    <Animated.ScrollView
      style={styles.container}
      onScroll={(e) => handleScroll(e)}
      bounces={shouldBounce}
      showsVerticalScrollIndicator={false}
      scrollEventThrottle={1}
      stickyHeaderIndices={[4]}
      refreshControl={
        <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
      }>
      <Cover {...{userXId, screenType}} />
      <ProfileCutout />
      <ProfileHeader
        {...{userXId, screenType, handleBlockUnblock, isBlocked}}
      />
      <ProfileBody
        {...{
          onLayout,
          userXId,
          screenType,
          isFriend,
          handleBlockUnblock,
          isBlocked,
        }}
      />
      <TaggsBar {...{y, profileBodyHeight, userXId, screenType}} />
      <View style={styles.momentsContainer}>
        {userXId && moments.length === 0 && (
          <View style={styles.plusIconContainer}>
            <GreyPlusLogo width={90} height={90} />
            <Text style={styles.noMomentsText}>{`Looks like ${
              profile.name.split(' ')[0]
            } has not posted any moments yet`}</Text>
          </View>
        )}
        {!userXId &&
          profile.profile_completion_stage === 2 &&
          !isStageTwoPromptClosed && (
            <TaggPrompt
              messageHeader={UPLOAD_MOMENT_PROMPT_TWO_HEADER}
              messageBody={UPLOAD_MOMENT_PROMPT_TWO_MESSAGE}
              logoType=""
              onClose={() => {
                setIsStageTwoPromptClosed(true);
              }}
            />
          )}
        {!userXId &&
          profile.profile_completion_stage === 3 &&
          !isStageThreePromptClosed && (
            <TaggPrompt
              messageHeader={UPLOAD_MOMENT_PROMPT_THREE_HEADER}
              messageBody={UPLOAD_MOMENT_PROMPT_THREE_MESSAGE}
              logoType=""
              onClose={() => {
                setIsStageThreePromptClosed(true);
              }}
            />
          )}
        {momentCategories.map(
          (title, index) =>
            (!userXId || imagesMap.get(title)) && (
              <Moment
                key={index}
                title={title}
                images={imagesMap.get(title)}
                userXId={userXId}
                screenType={screenType}
                handleMomentCategoryDelete={handleCategoryDeletion}
                shouldAllowDeletion={momentCategories.length > 1}
                showUpButton={index !== 0}
                showDownButton={index !== momentCategories.length - 1}
                move={move}
              />
            ),
        )}
        {!userXId && (
          <TouchableOpacity
            onPress={() =>
              navigation.push('CategorySelection', {
                screenType: CategorySelectionScreenType.Profile,
                user: loggedInUser,
              })
            }
            style={styles.createCategoryButton}>
            <Text style={styles.createCategoryButtonLabel}>
              Create a new category
            </Text>
          </TouchableOpacity>
        )}
      </View>
    </Animated.ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  momentsContainer: {
    backgroundColor: '#f2f2f2',
    paddingBottom: SCREEN_HEIGHT / 10,
    flex: 1,
    flexDirection: 'column',
  },
  createCategoryButton: {
    backgroundColor: TAGG_LIGHT_BLUE,
    justifyContent: 'center',
    alignItems: 'center',
    width: '70%',
    height: 30,
    marginTop: '15%',
    alignSelf: 'center',
  },
  createCategoryButtonLabel: {
    fontSize: normalize(16),
    fontWeight: '500',
    color: 'white',
  },
  plusIconContainer: {
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    marginVertical: '10%',
  },
  noMomentsText: {
    fontSize: normalize(14),
    fontWeight: 'bold',
    color: 'gray',
    marginVertical: '8%',
  },
});

export default Content;
