import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
import {Alert, Image, StyleSheet, Text, View} from 'react-native';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import LinearGradient from 'react-native-linear-gradient';
import {useDispatch, useStore} from 'react-redux';
import {BACKGROUND_GRADIENT_MAP} from '../../constants';
import {ERROR_DELETED_OBJECT} from '../../constants/strings';
import {loadImageFromURL} from '../../services';
import {
  acceptFriendRequest,
  declineFriendRequest,
  loadUserNotifications,
  updateReplyPosted,
  updateUserXFriends,
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {
  CommentNotificationType,
  CommentThreadType,
  MomentType,
  NotificationType,
  ScreenType,
  ThreadNotificationType,
  UserType,
} from '../../types';
import {fetchUserX, SCREEN_HEIGHT, userXInStore} from '../../utils';
import AcceptDeclineButtons from '../common/AcceptDeclineButtons';

interface NotificationProps {
  item: NotificationType;
  screenType: ScreenType;
  loggedInUser: UserType;
}

const Notification: React.FC<NotificationProps> = (props) => {
  const {
    item: {
      actor: {id, username, first_name, last_name, thumbnail_url},
      verbage,
      notification_type,
      notification_object,
      unread,
    },
    screenType,
    loggedInUser,
  } = props;

  const navigation = useNavigation();
  const state: RootState = useStore().getState();
  const dispatch = useDispatch();

  const [avatar, setAvatar] = useState<string | undefined>(undefined);
  const [momentURI, setMomentURI] = useState<string | undefined>(undefined);

  useEffect(() => {
    (async () => {
      const response = await loadImageFromURL(thumbnail_url);
      if (response) {
        setAvatar(response);
      } else {
        setAvatar(undefined);
      }
    })();
  }, []);

  useEffect(() => {
    let mounted = true;
    const setMomentThumbnailUrl = async (url: string) => {
      if (mounted && url) {
        setMomentURI(url);
      } else {
        // if not set to empty, it will re-use the previous notification's state
        setMomentURI(undefined);
      }
    };
    if (notification_object) {
      let url: string | undefined;
      let obj;
      if (
        notification_type === 'MOM_3+' ||
        notification_type === 'MOM_FRIEND'
      ) {
        obj = notification_object as MomentType;
        url = obj.thumbnail_url;
      } else if (notification_type === 'CMT') {
        obj = notification_object as CommentNotificationType;
        url = obj.notification_data.thumbnail_url;
      }
      if (url) {
        setMomentThumbnailUrl(url);
      }
    }
    return () => {
      mounted = false;
    };
  }, [id, notification_object, notification_type]);

  const onNotificationTap = async () => {
    switch (notification_type) {
      case 'FRD_ACPT':
      case 'FRD_REQ':
        if (!userXInStore(state, screenType, id)) {
          await fetchUserX(
            dispatch,
            {userId: id, username: username},
            screenType,
          );
        }
        navigation.push('Profile', {
          userXId: id,
          screenType,
        });
        break;
      case 'CMT':
        //Notification object is set to null if the comment / comment_thread / moment gets deleted
        if (!notification_object) {
          Alert.alert(ERROR_DELETED_OBJECT);
          break;
        }

        /**
         * Notification object knows
         *  1 - Which comment
         *  2 - Which user
         * The comment / reply belongs to
         * STEP 1 : Populate reply / comment
         * STEP 2 : Load user data if moment does not belong to the logged in user
         * STEP 3 : Navigate to relevant moment
         */

        let comment_id: string;
        let not_object;
        let reply: CommentThreadType | undefined;
        let userXId;

        // STEP 1
        if ('parent_comment' in notification_object) {
          //This is a reply
          not_object = notification_object as ThreadNotificationType;
          comment_id = not_object.parent_comment;
          reply = {
            parent_comment: {comment_id: comment_id},
            comment_id: not_object.comment_id,
          };
        } else {
          not_object = notification_object as CommentNotificationType;
          comment_id = not_object.comment_id;
        }

        //STEP 2
        const {user, ...moment} = not_object.notification_data;
        if (user.id !== loggedInUser.userId) {
          fetchUserX(
            dispatch,
            {userId: user.id, username: user.username},
            screenType,
          );
          userXId = user.id;
        }

        const {moment_id} = moment;

        //STEP 3
        if (moment) {
          //Now if moment was found, navigate to the respective moment
          if (reply) {
            dispatch(updateReplyPosted(reply));
          }
          navigation.push('IndividualMoment', {
            moment,
            userXId, // we're only viewing our own moment here
            screenType,
          });
          setTimeout(() => {
            navigation.push('MomentCommentsScreen', {
              moment_id: moment_id,
              screenType,
              comment_id: comment_id,
            });
          }, 500);
        }
        break;
      case 'MOM_3+':
      case 'MOM_FRIEND':
        const object = notification_object as MomentType;
        await fetchUserX(
          dispatch,
          {userId: id, username: username},
          screenType,
        );
        navigation.push('IndividualMoment', {
          moment: object,
          userXId: id,
          screenType,
        });
        break;
      default:
        break;
    }
  };

  const handleAcceptRequest = async () => {
    await dispatch(
      acceptFriendRequest({id, username, first_name, last_name, thumbnail_url}),
    );
    await dispatch(updateUserXFriends(id, state));
    dispatch(loadUserNotifications());
  };

  const handleDeclineFriendRequest = async () => {
    await dispatch(declineFriendRequest(id));
    dispatch(loadUserNotifications());
  };

  const renderContent = () => (
    <TouchableWithoutFeedback
      style={styles.container}
      onPress={onNotificationTap}>
      <View style={styles.avatarContainer}>
        <Image
          style={styles.avatar}
          source={
            avatar
              ? {uri: avatar}
              : require('../../assets/images/avatar-placeholder.png')
          }
        />
      </View>
      <View style={styles.contentContainer}>
        <Text style={styles.actorName}>
          {first_name} {last_name}
        </Text>
        <Text>{verbage}</Text>
      </View>
      {notification_type === 'FRD_REQ' && (
        <View style={styles.buttonsContainer}>
          <AcceptDeclineButtons
            requester={{id, username, first_name, last_name}}
            onAccept={handleAcceptRequest}
            onReject={handleDeclineFriendRequest}
          />
        </View>
      )}
      {(notification_type === 'CMT' ||
        notification_type === 'MOM_3+' ||
        notification_type === 'MOM_FRIEND') &&
        notification_object && (
          <Image style={styles.moment} source={{uri: momentURI}} />
        )}
    </TouchableWithoutFeedback>
  );

  return unread ? (
    <LinearGradient colors={BACKGROUND_GRADIENT_MAP[2]} useAngle angle={90}>
      {renderContent()}
    </LinearGradient>
  ) : (
    renderContent()
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    height: Math.round(SCREEN_HEIGHT / 10),
    flex: 1,
    alignItems: 'center',
  },
  avatarContainer: {
    marginLeft: '8%',
    flex: 1,
    justifyContent: 'center',
  },
  avatar: {
    height: 42,
    width: 42,
    borderRadius: 20,
  },
  contentContainer: {
    flex: 5,
    marginLeft: '5%',
    height: '80%',
    flexDirection: 'column',
    justifyContent: 'space-around',
    marginRight: '15%',
  },
  actorName: {
    fontSize: 15,
    fontWeight: '700',
  },
  moment: {
    position: 'absolute',
    height: 42,
    width: 42,
    right: '5%',
  },
  buttonsContainer: {},
});

export default Notification;
