    // This file houses crud methods to interact with landmarks on the server. They are generally called by react query mutations.

    import axios, { AxiosRequestConfig } from "axios"
    import { Region } from "react-native-maps";
    import { QueryClient, useMutation, useQuery, useQueryClient } from "react-query";
    import { API_URL, reportAxiosError as reportAxiosError } from "../globals"
    import { authStore } from "../stores/AuthStore";
    import { useAuth } from "./useAuth";

    /**
     * Interface representing a landmark's comment.
     */
    export interface LMComment {
        /**
         * The comment's id.
         */
        id: string,
        /**
         * The id of the user who posted the comment
         */
        poster: string,
        /**
         * The text content of the comment
         */
        text: string
        /**
         * The landmark that this comment is associated with.
         */
        landmark: Landmark
    }

    /**
     * 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 longitude of the landmark's location.
         */
        longitude?: number | null,
        /**
         * The 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,
        /**
         * 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
    }

    /**
     * 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 = (region: Region | undefined) => {
        const { refreshAccessToken } = useAuth();

        /**
         * 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:")
            console.log(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 getLandmarks = async (region: Region | undefined) => {
            // if (region) {
                const config: AxiosRequestConfig = {
                method: 'GET',
                // url: `${API_URL}/api/landmarks/?lat=${region.latitude}&long=${region.longitude}&lat_delta=${region.latitudeDelta}&long_delta=${region.longitudeDelta}`,
                url: `${API_URL}/api/landmarks/`,
                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 landmarks', error)
                throw new Error;
            }
            // }
            // else {
            //     return [];
            // }
        }

         /**
         * The callback responsible for adding a new {@link Landmark} to the server, used by the [react-query useMutation]{@link https://react-query.tanstack.com/reference/useMutation#_top} hook.
         * * @memberOf useLandmarks
         */
        const createLandmark = async (landmarkValue: Landmark | undefined): Promise<Landmark | undefined> => {
            const config: AxiosRequestConfig = {
                method: 'POST',
                data: landmarkValue,
                url: API_URL + `/api/landmark/`,
                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 landmarks', error)
                throw new Error;
            }
        }

        /**
         * The callback responsible for updating a {@link Landmark} on the server, used by the [react-query useMutation]{@link https://react-query.tanstack.com/reference/useMutation#_top} hook.
         * * @memberOf useLandmarks
         */
        const editLandmark =  async (landmarkValue: Landmark) => {
            const config: AxiosRequestConfig = {
                method: 'PUT',
                data: landmarkValue,
                url: API_URL + `/api/landmark/`,
                headers: { "Authorization": "Bearer " + authStore.accessToken, }
            }

            console.log(landmarkValue)

            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 landmarks', error)
                throw new Error;
            }
        }

        /**
         * The callback responsible for deleting a {@link Landmark} from the server, used by the [react-query useMutation]{@link https://react-query.tanstack.com/reference/useMutation#_top} hook.
         * * @memberOf useLandmarks
         */
        const removeLandmark =  async (id?: string | null) => {
            const config: AxiosRequestConfig = {
                method: 'DELETE',
                url: API_URL + `/api/landmark/${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()

                        // add new access token to header
                        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 landmarks', error)
                throw new Error;
            }
        }

        // get-all query
        const { data: landmarks, status: getLandmarksStatus, refetch: refetchLandmarks } = useQuery<Landmark[], Error>(['getLandmarks', region], () => getLandmarks(region), {
            placeholderData: () => queryClient.getQueryData('getLandmarks'),
            staleTime: 1000,
            refetchInterval: 30000,
            refetchOnReconnect: true,
            refetchOnMount: false
        })

        // mutations
        const { status: addLandmarkStatus, mutateAsync: addLandmarkAsync, reset: resetAddLm, data: newLandmark } = useMutation(createLandmark, {
            onSuccess: data => {
                queryClient.invalidateQueries('getLandmarks')
            },
        })

        const { status: updateLandmarkStatus, mutateAsync: updateLandmark, reset: resetUpdateLm } = useMutation(editLandmark, {
            onSuccess: () => queryClient.invalidateQueries('getLandmarks'),
            onError: () => queryClient.invalidateQueries('getLandmarks'),
        })

        const { status: deleteLandmarkStatus, mutateAsync: deleteLandmark, reset: resetDeleteLm } = useMutation(removeLandmark, {
            onSuccess: () => queryClient.invalidateQueries('getLandmarks'),
            onError: () => queryClient.invalidateQueries('getLandmarks'),
        })

        return {
            landmarks, getLandmarksStatus, refetchLandmarks,  //reading
            addLandmarkAsync, resetAddLm, addLandmarkStatus, newLandmark, // creating
            updateLandmark, resetUpdateLm, updateLandmarkStatus, // updating
            deleteLandmark, resetDeleteLm, deleteLandmarkStatus, // deleting
        }
    }