import {createContext, FC, ReactNode, useContext, useEffect, useState} from "react";
import * as SplashScreen from "expo-splash-screen";
import auth, {FirebaseAuthTypes} from "@react-native-firebase/auth";
import {useRouter} from "expo-router";
import firestore from "@react-native-firebase/firestore";
import {UserProfile} from "@/hooks/firebase/types/profileTypes";

import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import Constants from 'expo-constants';
import {Platform} from 'react-native';
import {useQueryClient} from "@tanstack/react-query";


export enum ProfileType {
    "PARENT" = "parent",
    "CHILD" = "child",
    "CAREGIVER" = "caregiver",
    FAMILY_DEVICE = "FAMILY_DEVICE"
}

interface IAuthContext {
    user: FirebaseAuthTypes.User | null,
    profileType?: ProfileType,
    profileData?: UserProfile,
    setProfileData: (profileData: UserProfile) => void,
    setRedirectOverride: (val: boolean) => void,
    refreshProfileData: () => Promise<void>
}

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

Notifications.addNotificationReceivedListener(notification => {
    console.log('Notification received:', notification);
});

async function registerForPushNotificationsAsync() {
    if (Platform.OS === 'android') {
        await Notifications.setNotificationChannelAsync('default', {
            name: 'default',
            importance: Notifications.AndroidImportance.MAX,
            vibrationPattern: [0, 250, 250, 250],
            lightColor: '#FF231F7C',
        });
    }

    if (Device.isDevice) {
        const {status: existingStatus} = await Notifications.getPermissionsAsync();
        let finalStatus = existingStatus;

        if (existingStatus !== 'granted') {
            const {status} = await Notifications.requestPermissionsAsync();
            finalStatus = status;
        }

        if (finalStatus !== 'granted') {
            // alert('Failed to get push token for push notification!');
            return;
        }

        const projectId =
            Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;

        if (!projectId) {
            alert('Project ID not found');
            return;
        }

        try {
            const token = (await Notifications.getExpoPushTokenAsync({projectId})).data;
            console.log('Push Token:', token);
            return token;
        } catch (error) {
            // alert(`Error getting push token: ${error}`);
            throw error;
        }
    } else {
        // alert('Must use a physical device for push notifications');
    }
}

const AuthContext = createContext<IAuthContext>(undefined!)

export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) => {
    const [user, setUser] = useState<FirebaseAuthTypes.User | null>(null);
    const [initializing, setInitializing] = useState(true);
    const [profileType, setProfileType] = useState<ProfileType | undefined>(undefined);
    const [profileData, setProfileData] = useState<UserProfile | undefined>(undefined);
    const [redirectOverride, setRedirectOverride] = useState(false);

    const {replace} = useRouter();
    const ready = !initializing;

    const queryClient = useQueryClient();

    const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => {
        if (!redirectOverride) {

            setUser(authUser);

            if (authUser) {
                await refreshProfileData(authUser);
                const pushToken = await registerForPushNotificationsAsync();
                if (pushToken) {
                    await savePushTokenToFirestore(authUser.uid, pushToken);
                }
            }

            if (initializing) setInitializing(false);
        }
    };

    const refreshProfileData = async (user?: FirebaseAuthTypes.User) => {
        const authUser = user ?? auth().currentUser
        if (authUser) {
            try {
                const documentSnapshot = await firestore()
                    .collection("Profiles")
                    .doc(authUser.uid)
                    .get();
                if (documentSnapshot.exists) {
                    setProfileType(documentSnapshot.data()?.userType);
                    setProfileData(documentSnapshot.data() as UserProfile);
                }
            } catch (error) {
                setProfileType(undefined);
                setProfileData(undefined);
            }
        }
    };

    const savePushTokenToFirestore = async (uid: string, token: string) => {
        try {
            await firestore().collection("Profiles").doc(uid).update({
                pushToken: token,
            });
        } catch (error) {
            console.error('Error saving push token to Firestore:', error);
        }
    };

    useEffect(() => {
        const subscriber = auth().onAuthStateChanged(onAuthStateChangedHandler);
        return subscriber;
    }, []);

    useEffect(() => {
        if (!initializing) {
            if(auth().currentUser) {
                setTimeout(() => SplashScreen.hideAsync(), 1000);
            } else {
                SplashScreen.hideAsync();
            }
        }
    }, [initializing]);

    useEffect(() => {
        if (ready && user && !redirectOverride) {
            replace({pathname: "/(auth)/calendar"});
        } else if (ready && !user && !redirectOverride) {
            replace({pathname: "/(unauth)"});
        }
    }, [user, ready, redirectOverride]);

    useEffect(() => {
        const handleNotification = async (notification: Notifications.Notification) => {
            queryClient.invalidateQueries({queryKey: ["notifications"]});
        };

        const sub = Notifications.addNotificationReceivedListener(handleNotification);

        return () => sub.remove();
    }, []);

    if (!ready) {
        return null;
    }

    return (
        <AuthContext.Provider
            value={{user, profileType, profileData, setProfileData, refreshProfileData, setRedirectOverride}}>
            {children}
        </AuthContext.Provider>
    );
};


export const useAuthContext = () => useContext(AuthContext)!;
