    import { FontAwesome } from "@expo/vector-icons";
    import * as Location from 'expo-location';
    import React, { useEffect, useState } from "react";
    import { Keyboard, KeyboardAvoidingView, TouchableOpacity, View } from "react-native";
    import MapView, { LatLng, Region } from "react-native-maps";
    import Modal from "react-native-modal";
    import { colors } from "../globals";
    import { Landmark, useLandmarks } from "../hooks/useLandmarks";
    import AddLandmark from "./AddLandmark";
    import LandmarkDetails from "./LandmarkDetails";
    import LandmarkPin from "./LandmarkPin";

    /**
     * An interface representing the user location retrieved from [expo-location]{@link https://docs.expo.dev/versions/latest/sdk/location/}.
     * @category Map
     */
    export interface UserLocation {
        latitude: number;
        longitude: number;
        heading?: number;
    }

    const directionsUrl = "https://maps.googleapis.com/maps/api/directions/son?mode=walking&alternatives=true&key=AIzaSyD06YUMazlb4Fu0Q81y_YNyEBz8PmtZyeY";

    /**
     * The screen component containing the [react-native-maps]{@link https://github.com/react-native-maps/react-native-maps} Map and all related functionality.
     * @category Map
     * @component
     */
    export const Map: React.FC = () => {
        /**
         * State that contains the new {@link Landmark} object which is passed down to the {@link AddLandmark} modal.
         */
        const newLandmarkState: Landmark = {};
        const [newLandmark, setNewLandmark] = useState<Landmark>(newLandmarkState);
        /**
         * State that contains the selected {@link Landmark} object which is passed down to the {@link LandmarkDetails} modal.
         */
        const selectedLandmarkState: Landmark = {};
        const [selectedLandmark, setSelectedLandmark] = useState<Landmark>(selectedLandmarkState);
        /**
         * Holds the visibility state of the {@link AddLandmark} modal.
         */
        const lmAddVisibleState = false;
        const [lmAddVisible, toggleLmAdd] = useState<boolean>(false);
        /**
         * Holds the visibility state of the {@link LandmarkDetails} modal.
         */
        const lmDetailsVisibleState = false;
        const [lmDetailsVisible, toggleLmDetails] = useState<boolean>(false);
        /**
         * Flag that toggles whether or not editing is enabled in the {@link LandmarkDetails} modal.
         * The parent Map component has access to it so that it can disable closing the modal on backdrop press when it is enabled.
         */
        const lmDetailsEditingState = false;
        const [lmDetailsEditing, toggleLmDetailsEditing] = useState<boolean>(false);
        /**
         * State that holds a {@link UserLocation} object retrieved from location services.
         */
        const userLocationState: UserLocation | undefined = undefined;
        const [userLocation, setUserLocation] = useState<UserLocation>(userLocationState);
        /**
         * Flag that determines whether the map should focus and follow the user's location.
         */
        const followUserState = false;
        const [followUser, toggleFollowUser] = useState<boolean>(followUserState);
        //const [prevFetchedBounds, setFetchedBounds] = useState<Region>();
        const { landmarks, getLandmarksStatus, refetchLandmarks } = useLandmarks(undefined);

        /**
         * Ref that holds the loaded [MapView]{@link https://github.com/react-native-maps/react-native-maps/blob/master/docs/mapview.md} instance.
         */
        const mapRef = React.createRef<MapView>();

        useEffect(() => {
            /**
             * Prompts user to give permission to track their location using [expo-location]{@link https://docs.expo.dev/versions/latest/sdk/location/}.
             * If permission is granted, user location will be retrieved and stored in {@linkcode userLocationState}.
             * @memberOf Map
             */
            const requestLocationPermissions = async () => {
                let { status } = await Location.requestForegroundPermissionsAsync();
                if (status !== 'granted') {
                    return;
                }

                const location = await Location.getCurrentPositionAsync();
                setUserLocation({latitude: location.coords.latitude, longitude: location.coords.longitude})
                // setFetchedBounds({
                //     latitude: location.coords.latitude,
                //     longitude: location.coords.longitude,
                //     latitudeDelta: 0.01,
                //     longitudeDelta: 0.01
                // });
            };

            requestLocationPermissions();
        }, []);

        /**
         * Triggered by long pressing on the map.
         * Sets {@linkcode newLandmarkState} to a skeleton {@link Landmark} object that only contains the pressed coordinates.
         * Triggers {@link openAddLandmark} via useEffect because the asyncronous nature of useState does not set the coordinates fast enough to toggle the modal directly through this method.
         */
         const promptAddLandmark = (coordinate: LatLng) => {
            setNewLandmark({latitude: coordinate.latitude, longitude: coordinate.longitude});
        }

        useEffect(() => {
            /**
             * Opens the {@link AddLandmark} modal when the user creates {@link newLandmarkState} by longpressing the map.
             * Embedded in a [useEffect]{@link https://reactjs.org/docs/hooks-effect.html} hook that listens to {@linkcode newLandmarkState}.
             * @memberOf Map
             */
            function openAddLandmark() {
                if (newLandmark) {
                    toggleLmAdd(true)
                    toggleLmDetails(false)
                    console.log(newLandmark)
                }
            }
            openAddLandmark();
        }, [newLandmark]);

        // useEffect(() => {
        //     if (prevFetchedBounds) {
        //         refetchLandmarks();
        //     }
        // }, [prevFetchedBounds]);

        /**
         * Triggered by on a {@link Landmark} displayed on the map.
         * Sets {@linkcode selectedLandmark} to the pressed {@link Landmark} object's value and toggles the {@link LandmarkDetails} modal.
         */
        const focusLandmark = (landmark: Landmark) => {
            setSelectedLandmark(landmark);
            toggleLmDetails(true)
        }

        /**
         * Animates the map to fly over to and focus on the user's location.
         */
        const flyToUser = () => {
            if (userLocation) {
                mapRef.current?.animateToRegion({latitude: userLocation.latitude, longitude: userLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01})
            }
        }

        // const checkBounds = (bounds: Region) => {
        //     if (prevFetchedBounds) {
        //         if (
        //             bounds.latitude < prevFetchedBounds.latitude - prevFetchedBounds.latitudeDelta || // check if new lat exceeds old left bounds
        //             bounds.latitude > prevFetchedBounds.latitude + prevFetchedBounds.latitudeDelta || // check if new lat exceeds old right bounds
        //             bounds.longitude < prevFetchedBounds.longitude - prevFetchedBounds.longitudeDelta || // check if new lat exceeds bottom bounds
        //             bounds.longitude > prevFetchedBounds.longitude + prevFetchedBounds.longitudeDelta ||
        //             bounds.latitudeDelta < prevFetchedBounds.latitudeDelta / 2) // check if user zoomed in to atleast half scale of previous
        //         {
        //             console.log('new bounds')
        //             setFetchedBounds(bounds);
        //         }
        //     }
        //     else if (bounds.latitudeDelta < 5) {
        //         console.log('initialize bounds')
        //         setFetchedBounds(bounds);
        //     }
        // }

        return (
            <View>
                <MapView
                    testID="mapView"
                    ref={mapRef}
                    style={{width: "100%", height: "100%"}}
                    initialRegion={userLocation ? {latitude: userLocation.latitude, longitude: userLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01} : undefined}
                    onLongPress={e => promptAddLandmark(e.nativeEvent.coordinate)}
                    // onRegionChangeComplete={bounds => checkBounds(bounds)}
                    showsUserLocation={true}
                    onUserLocationChange={e => setUserLocation(e.nativeEvent.coordinate)}
                    followsUserLocation={followUser}>
                {landmarks?.map((landmark) => {
                    return (
                    <LandmarkPin key={landmark.id} landmark={landmark} focusLandmark={focusLandmark}/>)})}
                </MapView>
                <TouchableOpacity style={{position: 'absolute', bottom: 30, right: 30, backgroundColor: colors.red, height: 60, width: 60, borderRadius: 30, justifyContent: "center", alignItems: 'center'}} onPress={flyToUser}>
                    <FontAwesome name="location-arrow" size={20} color="white"/>
                </TouchableOpacity>
                {/* <TouchableOpacity style={{position: 'absolute', bottom: 120, right: 30, backgroundColor: colors.red, height: 60, width: 60, borderRadius: 30, justifyContent: "center", alignItems: 'center'}}>
                    <FontAwesome name="" size={20} color="white"/>
                </TouchableOpacity> */}
                <Modal
                    testID="addLMModal"
                    avoidKeyboard={true}
                    onBackdropPress={() => toggleLmAdd(false)}
                    style={{justifyContent: "flex-end", height: '100%', margin: 0}}
                    isVisible={lmAddVisible} >
                    <KeyboardAvoidingView>
                        <AddLandmark setVisible={toggleLmAdd} landmark={newLandmark} />
                    </KeyboardAvoidingView>
                </Modal>
                <Modal
                    avoidKeyboard={true}
                    onBackdropPress={() => {
                        if (lmDetailsEditing) {
                            Keyboard.dismiss();
                        } else {
                            toggleLmDetails(false)
                        }
                    }}
                    style={{justifyContent: "flex-end", height: '100%', margin: 0}}
                    isVisible={lmDetailsVisible}>
                    <LandmarkDetails setVisible={toggleLmDetails} setEditing={toggleLmDetailsEditing} editingEnabled={lmDetailsEditing} landmark={selectedLandmark} />
                </Modal>
            </View> )
    }