/* Copyright (C) Click & Push Accessibility, Inc - All Rights Reserved
 * Unauthorized copying of this file, via any medium is strictly prohibited
 * Proprietary and confidential
 * Written and maintained by the Click & Push Development team 
 * <dev@clicknpush.ca>, January 2022
 */

import { AxiosRequestConfig } from "axios";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useAuth } from "./auth-provider";
import { LMComment } from "./comments";
import { queryKeys } from "./query-keys";

/**
 * Interface representing a landmark object
 */
export interface Landmark {
    /*** The id of the landmark.*/
    id?: string | null,
    /*** The rating of the landmark.*/
    rating?: number | null,
    /*** The id of the user who created the landmark.*/
    user?: string | null,
    /*** The x coordinate (or longitude) of the landmark's location.*/
    longitude?: number | null,
    /*** The y coordinate (or latitude) of the landmark's location.*/
    latitude?: number | null, 
    /*** The landmark's title.*/
    title?: string | null,
    /*** The landmark's description.*/
    description?: string | null,
    /*** User [comments]{@link LMComment} associated with this landmark.*/
    comments?: LMComment[] | null,
    /*** [Photos]{@link LMPhoto} associated with this landmark.*/
     photos?: LMPhoto[] | null,
    /*** An integer representing the type of this landmark.*/
    landmark_type?: number | null, // for working with existing database schema, should be changed
    /*** A Date object representing when this landmark was created.*/
    time?: Date | null,
    // DONE! 
    floor?: number | null,
    anonymous?: string,
    voice?: boolean
}

export interface LMPhoto {
    id: string
    landmark: string,
    image_b64: string
    height: number,
    width: number
}

export interface UseLandmarkOptions {
    userId?: string
    landmarkId?: string
    userLMPairing?: {userId?: string, landmarkId?: string}
    changingPassword?: boolean
}

interface AddLandmarkData {
    landmark: Landmark;
    photos?: LMPhoto[];
    indoorMapSnapshotBase64?: string;
}

/**
 * A custom hook containing [react-query]{@link https://react-query.tanstack.com/} queries and mutations and other logic related to interacting with {@link Landmark} objects.
 * @category Hooks
 * @namespace useLandmarks
 */
export const useLandmarks = () => {
    const { sendApiRequestAsync } = useAuth();
    const queryClient = useQueryClient();

    const getLandmarks = async () => {
        const response = await sendApiRequestAsync({
           axiosConfig:  {
                method: 'GET',
                url: `/api/landmarks/`,
            }, 
            authorized: false,
            errorMessage: 'Something went wrong when retrieving landmarks',
            loggingCategory: 'LANDMARKS'
        });   
        return response?.data
    }

    return useQuery<Landmark[], Error>(queryKeys.GET_LANDMARKS, () => getLandmarks(), {
        placeholderData: () => queryClient.getQueryData(queryKeys.GET_LANDMARKS),
        staleTime: 1000,
        refetchInterval: 30000,
        refetchOnReconnect: true,
        refetchOnMount: false
    })
}

export const useLandmark = (landmarkId: string) => {
    const {sendApiRequestAsync, userId} = useAuth()
    const queryClient = useQueryClient();

     const getLandmark = async (landmarkId?: string) => {
        if (landmarkId) {
            const response = await sendApiRequestAsync({
                axiosConfig: {
                    method: 'GET',
                    url: `/api/landmark/${landmarkId}/`,
                },
                authorized: !!userId,
                errorMessage: 'Something went wrong when retrieving the landmark',
                loggingCategory: 'LANDMARKS'
            });   
            return response?.data 
        }
    }

    return useQuery<{landmark: Landmark, ratedByUser: boolean}, Error>([queryKeys.GET_LANDMARKS, landmarkId], () => getLandmark(landmarkId), {
        placeholderData: () => queryClient.getQueryData(queryKeys.GET_LANDMARKS),
        refetchOnReconnect: true,
        refetchOnMount: false
    })
}

export const useAddLandmark = () => {
    const {sendApiRequestAsync, userId, anonUserId} = useAuth()
    const queryClient = useQueryClient();

    const createLandmark = async (data: AddLandmarkData): Promise<Landmark | undefined> => {
        if (data.landmark) {

            // attach landmark owner's id
            if (userId) {
                data.landmark.user = userId
            } else if (anonUserId) {
                data.landmark.anonymous = anonUserId
            }
            else {
                console.warn("[LandmarkData]: Couldn't create landmark, user id or anon id wasn't given.")
                return
            }

            console.log(data)

            const response = await sendApiRequestAsync({
                axiosConfig: {
                    method: 'POST',
                    url: `/api/landmark/`,
                    data: {
                        landmark: data.landmark,
                        photos: data.photos,
                        indoorLmLocImg: data.indoorMapSnapshotBase64
                    },
                },
                authorized: true,
                errorMessage: "Something went wrong when creating a landmark",
                loggingCategory: "LANDMARKS"
            });   
            return response?.data;
        }
        else {
            console.warn("[LandmarkData]: Can't create landmark. Given landmark value is null.")
        }
    }

    return useMutation(createLandmark, {
        onSuccess: landmark => {
            queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)
        },  
    })
}     

export const useEditLandmark = () => {
    const {sendApiRequestAsync, accessToken, anonUserId} = useAuth()
    const queryClient = useQueryClient();

    const editLandmark =  async (landmarkValue: Landmark) => {
        if (landmarkValue) {
            const config: AxiosRequestConfig = {
                method: 'PUT',
                url: `/api/landmark/`,
                data: {
                    landmark: landmarkValue
                }
            }

            if (!accessToken) {
                config.data = {...config.data, anonymous: anonUserId}
            }

            const response = await sendApiRequestAsync({
                axiosConfig: config, 
                authorized: true,
                errorMessage: 'Something went wrong when updating a landmark',
                loggingCategory: 'LANDMARKS'
            });   
            return response?.data;
        }
        else {
            console.warn("[LandmarkData]: Can't update landmark. Given landmark value is null.")
        }
    }

    return useMutation(editLandmark, {
        onSuccess: () => { queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)},  
        onError: () => queryClient.invalidateQueries(queryKeys.GET_LANDMARKS),  
    })
}

export const useRateLandmark = () => {
    const {sendApiRequestAsync} = useAuth()
    const queryClient = useQueryClient();

    const rateLandmark =  async (data: {id: string, rating: 1 | -1}) => {
        if (data) {
            const response = await sendApiRequestAsync({
                axiosConfig:{
                    method: 'POST',
                    data: data,
                    url: `/api/landmark/rate/`,
                },
                authorized: true,
                errorMessage: 'Something went wrong when rating a landmark',
                loggingCategory: 'LANDMARKS'
            });   
            return response?.data?.rating;
        }
    }

    return useMutation(rateLandmark, {
        onSuccess: () => { 
            queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)
        },  
        onError: () => queryClient.invalidateQueries(queryKeys.GET_LANDMARKS),  
    })    
}

export const useDeleteLandmark = () => {
    const {sendApiRequestAsync, accessToken, anonUserId} = useAuth()
    const queryClient = useQueryClient();

    const deleteLandmark =  async (id?: string) => {
        if (id) {
            const config: AxiosRequestConfig = {
                method: 'DELETE',
                url: `/api/landmark/${id}/`,
            }

            if (!accessToken) config.data = {...config.data, anonymous: anonUserId}


            const response = await sendApiRequestAsync({
                axiosConfig: config,
                authorized: true,
                errorMessage: 'Something went wrong when deleting a landmark',
                loggingCategory: 'LANDMARKS'
            });   
            return response?.data;
        }
    }

    return useMutation(deleteLandmark, {
        onSuccess: () => queryClient.invalidateQueries(queryKeys.GET_LANDMARKS),  
        onError: () => queryClient.invalidateQueries(queryKeys.GET_LANDMARKS),  
    })
}

export const useAddLandmarkPhoto = () => {
    const {sendApiRequestAsync, accessToken, anonUserId} = useAuth()
    const queryClient = useQueryClient();

    const addLandmarkPhoto = async (photo: LMPhoto) => {
        if (photo) {
            const config: AxiosRequestConfig = {
                method: 'POST',
                url: `/api/landmark/photos/`,
                data: photo
            }
        
            if (!accessToken) config.data = {...config.data, anonymous: anonUserId}

            const response = await sendApiRequestAsync({
                axiosConfig: config, 
                authorized: true,
                errorMessage: 'Something went wrong when adding landmark photo',
                loggingCategory: 'LANDMARKS'
            });   
            return response?.data
        }
    }

    return useMutation(addLandmarkPhoto, {
        onSuccess: () => {
            queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)
        },
        
        onError: () => {
            queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)
        },
    })
} 

export const useDeleteLandmarkPhoto = () => {
    const {sendApiRequestAsync, accessToken, anonUserId} = useAuth()
    const queryClient = useQueryClient();

    const deleteLandmarkPhoto = async (photoId: string) => {
        if (photoId) {
            const config: AxiosRequestConfig = {
                method: 'DELETE',
                url: `/api/landmark/photos/${photoId}/`
            }

            if (!accessToken) {
                config.data = {...config.data, anonymous: anonUserId}
            }

            const response = await sendApiRequestAsync({
                axiosConfig: config,
                authorized: true,
                errorMessage: 'Something went wrong when deleting landmark photos',
                loggingCategory: 'LANDMARKS'
            });   
            return response?.data
        }
    }

    return useMutation(deleteLandmarkPhoto, {
        onSuccess: () => {
            queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)
        },
        
        onError: () => {
            queryClient.invalidateQueries(queryKeys.GET_LANDMARKS)
        },
    })
}   