import axios, { AxiosRequestConfig } from "axios";
import { QueryClient, useMutation, useQuery, useQueryClient } from "react-query";
import { authStore } from "../stores/AuthStore";
import { RegisterCredsValues } from "../utils/RegistrationUtils";
import { API_URL, reportAxiosError } from "../utils/RequestUtils";
import { useAuth } from "./useAuth";

/**
 * Interface that contains data in a user's profile.
 */
export interface UserProfile {
    /**
     * The user's id
     */
    id?: string
    /**
     * The user's username
     */
    username?: string
    /**
     * The user's email
     */
    email?: string
    /**
     * The user's base64 encoded profile picture.
     */
    image_b64?: string
    /**
     * The user's preference for seeing tips.
     */
    show_tips?: boolean
}

export interface UserNotification {
    id: string
    user: string
    title: string
    data: string
    read: boolean
}

/**
 * A custom hook containing [react-query]{@link https://react-query.tanstack.com/} queries and mutations and other logic related to interacting with {@link UserProfile} objects.
 * @category Hooks
 * @namespace useProfile
 */
export const useProfile = (userId: string) => {
    /**
     * The local instance of the [react-query QueryClient]{@link https://react-query.tanstack.com/reference/QueryClient#_top}.
     * @memberOf useLandmarks
     */
    let queryClient: QueryClient;

    try {
        queryClient = useQueryClient()
    } catch (error) {
        console.log("Something went wrong when retrieving query client: " + error)
    }

    const { refreshAccessToken } = useAuth();

     /**
     * The callback responsible for retrieving the {@link Profile} matching the given ID from the API , used by the [react-query useQuery]{@link https://react-query.tanstack.com/reference/useQuery#_top} hook.
     * * @memberOf useProfile
     */
    const getProfile = async (id: string) => {
        if (userId) {
        const config: AxiosRequestConfig = {
            method: 'GET',
            url: API_URL + `/api/user-profile/${id}/`,
            headers: { "Authorization": "Bearer " + authStore.accessToken, }
        } 
        try {
            const response = await axios(config);   
            return response.data;
        } catch (error) {
            if (error.response.status == 401) {
                try {
                    await refreshAccessToken()    
                    const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                    return response.data;
                } catch (error) {
                    // refreshAccessToken will report errors
                }
            }

            reportAxiosError('Something went wrong when retrieving user profile', error)
            throw new Error;
        }
        
        }
    }

    /**
     * The callback responsible for retrieving {@link Landmark} from the API, used by the [react-query useQuery]{@link https://react-query.tanstack.com/reference/useQuery#_top} hook.
     * * @memberOf useLandmarks
     */
    const getNotifications = async () => {
        if (authStore.userId) {
            let url = `${API_URL}/api/user-profile/notifications/${authStore.userId}/`   
            const config: AxiosRequestConfig = {
                method: 'GET',
                url: url,
                headers: { "Authorization": "Bearer " + authStore.accessToken, }
            } 
    
            try {
                const response = await axios(config);   
                return response.data
            } catch (error) {
                if (error.response.status == 401) {
                    try {
                        await refreshAccessToken()    
                        const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                        return response.data
                    } catch (error) {
                        // refreshAccessToken will report errors
                    }
                }
    
                reportAxiosError('Something went wrong when retrieving notifications', error)
                throw new Error;
            }   
        }
    }

    const markNotificationRead = async (notificationId: string) => {
        const config: AxiosRequestConfig = {
            method: 'POST',
            url: API_URL + `/api/user-profile/notifications/mark-read/${notificationId}/`,
            headers: { "Authorization": "Bearer " + authStore.accessToken, }
        } 
        try {
            const response = await axios(config);   
            return response.data;
        } catch (error) {
            if (error.response.status == 401) {
                try {
                    await refreshAccessToken()    
                    const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                    return response.data;
                } catch (error) {
                    // refreshAccessToken will report errors
                }
            }

            reportAxiosError('Something went wrong when editing user profile', error)
            throw new Error;
        }
    }

    const removeNotificaiton = async (notificationId: string) => {
        const config: AxiosRequestConfig = {
            method: 'DELETE',
            url: API_URL + `/api/user-profile/notifications/delete/${notificationId}/`,
            headers: { "Authorization": "Bearer " + authStore.accessToken, }
        } 
        try {
            const response = await axios(config);   
            return response.data;
        } catch (error) {
            if (error.response.status == 401) {
                try {
                    await refreshAccessToken()    
                    const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                    return response.data;
                } catch (error) {
                    // refreshAccessToken will report errors
                }
            }

            reportAxiosError('Something went wrong when editing user profile', error)
            throw new Error;
        }
    }

    const editProfile = async (values: RegisterCredsValues) => {
        if (userId) {
            const config: AxiosRequestConfig = {
                method: 'PUT',
                url: API_URL + `/api/user-profile/${authStore.userId}/`,
                data: values,
                headers: { "Authorization": "Bearer " + authStore.accessToken, }
            } 
        try {
            const response = await axios(config);   
            return response.data;
        } catch (error) {
            if (error.response.status == 401) {
                try {
                    await refreshAccessToken()    
                    const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                    return response.data;
                } catch (error) {
                    // refreshAccessToken will report errors
                }
            }

            reportAxiosError('Something went wrong when editing user profile', error)
            throw new Error;
        }
        
        }
    }

    const changePassword = async (password: string) => {
        if (userId) {
            console.log(authStore.userId)
            const config: AxiosRequestConfig = {
                method: 'POST',
                url: API_URL + `/api/user-profile/change-password/${authStore.userId}/`,
                data: {password: password},
                headers: { "Authorization": "Bearer " + authStore.accessToken, }
            } 
            try {
                const response = await axios(config);   
                return response.data;
            } catch (error) {
                if (error.response.status == 401) {
                    try {
                        await refreshAccessToken()    
                        const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                        return response.data;
                    } catch (error) {
                        // refreshAccessToken will report errors
                    }
                }

                reportAxiosError('Something went wrong when editing user profile', error)
                throw new Error;
            }
            
        }
    }

    const changePicture = async () => {
        if (userId) {
            const config: AxiosRequestConfig = {
                method: 'POST',
                url: API_URL + `/api/user-profile/change-picture/${authStore.userId}/`,
                headers: { "Authorization": "Bearer " + authStore.accessToken, }
            }   
            try {
                const response = await axios(config);   
                return response.data;
            } catch (error) {
                if (error.response.status == 401) {
                    try {
                        await refreshAccessToken()    
                        const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                        return response.data;
                    } catch (error) {
                        // refreshAccessToken will report errors
                    }
                }
            }
        }
    }

    const toggleTips = async () => {
        if (userId) {
        const config: AxiosRequestConfig = {
            method: 'POST',
            url: API_URL + `/api/user-profile/toggle-tips/${authStore.userId}/`,
            headers: { "Authorization": "Bearer " + authStore.accessToken, }
        } 
        try {
            const response = await axios(config);   
            return response.data;
        } catch (error) {
            if (error.response.status == 401) {
                try {
                    await refreshAccessToken()    
                    const response = await axios({...config, headers: { "Authorization": "Bearer " + authStore.accessToken }});   
                    return response.data;
                } catch (error) {
                    // refreshAccessToken will report errors
                }
            }

            reportAxiosError('Something went wrong when editing user profile', error)
            throw new Error;
        }
        
        }
    }

    // get profile query
    const { data: profile, status: getProfileStatus, refetch: refetchProfile } = useQuery<UserProfile, Error>(['getProfile', userId], async () => getProfile(userId))
    // get notifications query
    const { data: notifications, status: getNotificationsStatus, refetch: refetchNotifications } = useQuery<UserNotification[], Error>(['getNotifications', userId], async () => getNotifications())
    // edit profile query
    const { status: updateProfileStatus, mutateAsync: updateProfile, reset: resetUpdateProfile } = useMutation(editProfile, {
        onSuccess: () => { queryClient.invalidateQueries('getProfile')},  
        onError: () => queryClient.invalidateQueries('getProfile'),  
    })

    const { status: markNotificationReadStatus, mutateAsync: markNotificationAsRead, reset: resetMarkNotificationRead } = useMutation(markNotificationRead, {
        onSuccess: () => { queryClient.invalidateQueries('getNotifications')},  
        onError: () => queryClient.invalidateQueries('getNotifications'),  
    })

    const { status: deleteNotificationStatus, mutateAsync: deleteNotification, reset: resetDeleteNotification } = useMutation(removeNotificaiton, {
        onSuccess: () => { queryClient.invalidateQueries('getNotifications')},  
        onError: () => queryClient.invalidateQueries('getNotifications'),  
    })

    // toggle tips
    const { status: changePasswordStatus, mutateAsync: changePasswordAsync, reset: resetChangePassword } = useMutation(changePassword, {
        onSuccess: () => { queryClient.invalidateQueries('getProfile')},  
        onError: () => queryClient.invalidateQueries('getProfile'),  
    })
    // toggle tips
    const { status: toggleTipsStatus, mutateAsync: toggleTipsAsync, reset: resetToggleTips } = useMutation(toggleTips, {
        onSuccess: () => { queryClient.invalidateQueries('getProfile')},  
        onError: () => queryClient.invalidateQueries('getProfile'),  
    })

    return { 
        profile, getProfileStatus, refetchProfile, //reading 
        updateProfile, updateProfileStatus, resetUpdateProfile, //editing
        notifications, getNotificationsStatus, refetchNotifications, //notifications 
        deleteNotification, deleteNotificationStatus, resetDeleteNotification, //delete notification
        markNotificationAsRead, markNotificationReadStatus, resetMarkNotificationRead, //update notifications 
        changePasswordAsync, changePasswordStatus, resetChangePassword, //changePassword
        toggleTipsAsync, toggleTipsStatus //toggleTips
     } 
}
