import React, { useEffect, useState, useContext, createContext } from 'react';
import * as Notifications from 'expo-notifications';
import { storage, StoreType } from 'src/storage';
import { AppState, AppStateStatus, Linking, Platform } from 'react-native';
import { CommonActions, useNavigation } from '@react-navigation/native';
import { NAVIGATION_PAGES } from 'src/types';
import { usePostSetSettingsMutation } from '@api/notifications';
import { useMessagesStore } from 'src/stores/unreadMessagesStore';
import { useFriendsNotificationsStore } from 'src/stores/friendsNotificationsStore';
import {
  handleNotificationData,
  registerBackgroundNotificationTask,
  unregisterBackgroundNotificationTask
} from 'src/utils/pushNotificationTask';

const PushNotificationContext = createContext<{
  isSubscribed: boolean;
  toggleSubscription: () => Promise<void>;
  unsubscribeFromNotifications: () => Promise<void>;
}>({
  isSubscribed: false,
  toggleSubscription: async () => {},
  unsubscribeFromNotifications: async () => {}
});

export const usePushNotification = () => useContext(PushNotificationContext);

export const PushNotificationProvider = ({ children }: { children: React.ReactNode }) => {
  const token = storage.get('token', StoreType.STRING) as string;
  const [isSubscribed, setIsSubscribed] = useState(
    (storage.get('subscribed', StoreType.BOOLEAN) as boolean) ?? false
  );
  const { mutateAsync: setNotificationsSettings } = usePostSetSettingsMutation();
  const navigation = useNavigation();
  const updateNotificationStatus = useFriendsNotificationsStore(
    (state) => state.updateNotificationStatus
  );
  const updateUnreadMessagesCount = useMessagesStore((state) => state.updateUnreadMessagesCount);
  const [appState, setAppState] = useState(AppState.currentState);

  const lastNotificationResponse = Notifications.useLastNotificationResponse();

  useEffect(() => {
    const handleAppStateChange = (nextAppState: AppStateStatus) => {
      if (appState.match(/inactive|background/) && nextAppState === 'active' && isSubscribed) {
        Notifications.getBadgeCountAsync().then((badgeCount) => {
          if (badgeCount > 0) {
            Notifications.setBadgeCountAsync(-1);
          }
        });
        Notifications.getPresentedNotificationsAsync().then((notifications) => {
          if (Platform.OS === 'ios' && notifications.length > 0) {
            notifications.forEach((notification) => {
              let groupToken;
              let messageId;
              let fromUser;
              const parsedData =
                JSON.parse(
                  (notification.request.trigger as Notifications.PushNotificationTrigger)?.payload
                    ?.params as string
                ) ?? {};
              groupToken = parsedData?.group_token;
              messageId = (notification.request.trigger as Notifications.PushNotificationTrigger)
                ?.payload?.message_id as number;
              fromUser = parsedData?.id;

              handleNotificationData(groupToken, messageId, fromUser);
            });
          }
        });
        updateNotificationStatus();
        updateUnreadMessagesCount();
      }
      setAppState(nextAppState);
    };

    const subscription = AppState.addEventListener('change', handleAppStateChange);

    return () => {
      subscription.remove();
    };
  }, [appState]);

  useEffect(() => {
    if (lastNotificationResponse && Platform.OS === 'android') {
      const data = lastNotificationResponse.notification.request.content.data;

      if (data?.screen && data?.parentScreen) {
        if (data?.params) {
          const parsedParams = JSON.parse(data.params) ?? {};

          navigation.dispatch(
            CommonActions.reset({
              index: 1,
              routes: [
                {
                  name: 'DrawerApp',
                  state: {
                    routes: [
                      {
                        name: data.parentScreen,
                        state: {
                          routes: [
                            { name: NAVIGATION_PAGES.MAP_TAB },
                            {
                              name: data.screen,
                              params: parsedParams
                            }
                          ]
                        }
                      }
                    ]
                  }
                }
              ]
            })
          );
        } else {
          navigation.dispatch(
            CommonActions.reset({
              index: 1,
              routes: [
                {
                  name: 'DrawerApp',
                  state: {
                    routes: [
                      {
                        name: data.parentScreen,
                        state: {
                          routes: [
                            { name: NAVIGATION_PAGES.MAP_TAB },
                            {
                              name: data.screen
                            }
                          ]
                        }
                      }
                    ]
                  }
                }
              ]
            })
          );
        }
      }
      if (data?.url) {
        Linking.openURL(data.url);
      }
    }
  }, [lastNotificationResponse]);

  const checkNotificationPermissions = async () => {
    const { status } = await Notifications.getPermissionsAsync();
    return status;
  };

  useEffect(() => {
    const getPermissionsStatus = async () => {
      const status = await checkNotificationPermissions();
      if (status !== 'granted' && isSubscribed) {
        await unsubscribeFromNotifications();

        return;
      }
    };

    if (isSubscribed) {
      getPermissionsStatus();

      Notifications.setNotificationHandler({
        handleNotification: async () => ({
          shouldShowAlert: true,
          shouldPlaySound: false,
          shouldSetBadge: false
        })
      });

      registerBackgroundNotificationTask();

      const notificationListener = Notifications.addNotificationReceivedListener((notification) => {
        updateNotificationStatus();
        updateUnreadMessagesCount();

        let groupToken;
        let messageId;
        let fromUser;
        if (Platform.OS === 'ios') {
          const parsedData =
            JSON.parse(
              (notification.request.trigger as Notifications.PushNotificationTrigger)?.payload
                ?.params as string
            ) ?? {};
          groupToken = parsedData?.group_token;
          messageId = (notification.request.trigger as Notifications.PushNotificationTrigger)
            ?.payload?.message_id as number;
          fromUser = parsedData?.id;

          handleNotificationData(groupToken, messageId, fromUser);
        }
      });

      const responseListener = Notifications.addNotificationResponseReceivedListener((response) => {
        let screenName;
        let url;
        let parentScreen;
        let params;
        if (Platform.OS === 'ios') {
          parentScreen = (
            response.notification.request.trigger as Notifications.PushNotificationTrigger
          )?.payload?.parentScreen;
          screenName = (
            response.notification.request.trigger as Notifications.PushNotificationTrigger
          )?.payload?.screen;
          params = (response.notification.request.trigger as Notifications.PushNotificationTrigger)
            ?.payload?.params;
          url = (response.notification.request.trigger as Notifications.PushNotificationTrigger)
            ?.payload?.url;
        }

        if (screenName && parentScreen) {
          if (params) {
            const parsedParams = JSON.parse(params as string) ?? {};

            navigation.dispatch(
              CommonActions.reset({
                index: 1,
                routes: [
                  {
                    name: 'DrawerApp',
                    state: {
                      routes: [
                        {
                          name: parentScreen as string,
                          state: {
                            routes: [
                              { name: NAVIGATION_PAGES.MAP_TAB },
                              {
                                name: screenName as string,
                                params: parsedParams
                              }
                            ]
                          }
                        }
                      ]
                    }
                  }
                ]
              })
            );
          } else {
            navigation.dispatch(
              CommonActions.reset({
                index: 1,
                routes: [
                  {
                    name: 'DrawerApp',
                    state: {
                      routes: [
                        {
                          name: parentScreen as string,
                          state: {
                            routes: [
                              { name: NAVIGATION_PAGES.MAP_TAB },
                              {
                                name: screenName as string
                              }
                            ]
                          }
                        }
                      ]
                    }
                  }
                ]
              })
            );
          }
        }
        if (url) {
          Linking.openURL(url as string);
        }
      });

      Notifications.getBadgeCountAsync().then((badgeCount) => {
        if (badgeCount > 0) {
          Notifications.setBadgeCountAsync(-1);
        }
      });

      return () => {
        notificationListener.remove();
        responseListener.remove();
      };
    } else {
      unregisterBackgroundNotificationTask();
    }
  }, [isSubscribed]);

  const subscribeToNotifications = async () => {
    storage.set('subscribed', true);
    setIsSubscribed(true);
  };

  const unsubscribeFromNotifications = async () => {
    const settings = {
      [Platform.OS === 'ios' ? 'app-ios' : 'app-android']: 0
    };

    await setNotificationsSettings({
      token,
      settings: JSON.stringify(settings)
    });

    storage.remove('deviceToken');
    storage.set('subscribed', false);
    setIsSubscribed(false);
    unregisterBackgroundNotificationTask();
  };

  const toggleSubscription = async () => {
    if (isSubscribed) {
      await unsubscribeFromNotifications();
    } else {
      await subscribeToNotifications();
    }
  };

  return (
    <PushNotificationContext.Provider
      value={{ isSubscribed, toggleSubscription, unsubscribeFromNotifications }}
    >
      {children}
    </PushNotificationContext.Provider>
  );
};
