import { FontAwesome } from "@expo/vector-icons"
import { useNavigation, useNavigationState, useRoute } from "@react-navigation/native"
import { createNativeStackNavigator } from "@react-navigation/native-stack"
import { StackNavigationProp } from "@react-navigation/stack"
import { observer } from "mobx-react"
import React, { useEffect, useState } from "react"
import { Image, Linking, ScrollView, Text, View } from "react-native"
import { Chip } from "react-native-paper"
import { IconButton } from "../Buttons"
import IndoorMap from "./indoor/IndoorMap"
import mapStyles from "./Map.styles"
import OutdoorMap, { AuthTabsMapRouteProp } from "./outdoor/outdoor-map.view"
import { useMapState } from "./useMapState"
import AddLandmarkPanel from "./panels/add-landmark-panel/add-landmark-panel.view"
import { FilterPanel } from "./panels/filter-panel/FilterPanel"
import LandmarkDetails from "./panels/LandmarkDetailsPanel/LandmarkDetails"
import { useAuth } from "../../state/external/auth-provider"
import { Landmark, useLandmarks } from '../../state/external/landmarks'
import { colors, lmTypes } from "../../utils/GlobalUtils"
import { MainTabsNavigationProp } from "../../navigation/main-tabs-navigator"
import { Menu, MenuDivider, MenuItem } from 'react-native-material-menu'
import { navigate } from "../../navigation/root-navigator"
import { addLandmarkStore } from "./panels/add-landmark-panel/add-landmark-panel.store"


const MapStackNavigator = createNativeStackNavigator()

export type MapStackParamList = {
    Outdoor: { selectedLandmark: string, selectedLandmarks: string[] },
    Indoor: React.FC,
}

export type MapStackNavigationProp = StackNavigationProp<MapStackParamList>

const MapNavigator: React.FC = () => {
    const { landmarkOwnedByUser } = useAuth()
    const mapState = useMapState()
    const authNavigation = useNavigation() as MainTabsNavigationProp
    const authRoute = useRoute() as AuthTabsMapRouteProp

    const landmarksQuery = useLandmarks();
    const navigationState = useNavigationState(state => state)
    const [currentRoute, setCurrentRoute] = useState<string>()

    const [visible, setVisible] = useState(false);

    useEffect(() => {
        const currentRouteIndex = navigationState?.routes[0]?.state?.index
        const currentRouteName = navigationState?.routes[0]?.state?.routeNames[currentRouteIndex]
        setCurrentRoute(currentRouteName)
    }, [navigationState])

    /**
     * Clear selected landmark when landmark details panel is closed
     */
    useEffect(() => {
        if (!mapState.lmDetailsVisible) {
            mapState.setSelectedLandmarkId('')
        }
    }, [mapState.lmDetailsVisible])

    useEffect(() => {
        const refetchLandmarksOnFilterOptionsChange = async () => {
            applyFilters(landmarksQuery?.data)
        }
        refetchLandmarksOnFilterOptionsChange()
    }, [mapState.lmFilteredTypes, mapState.onlyOwned, mapState.minLmRating])

    const applyFilters = (landmarks: Landmark[]): Landmark[] => {
        if (landmarks?.length > 0) {
            if (mapState.minLmRating > 0) {
                landmarks = landmarks?.filter(lm => lm && lm.rating >= mapState.minLmRating);
            }

            if (mapState.lmFilteredTypes?.length > 0) {
                landmarks = landmarks?.filter(lm => mapState.lmFilteredTypes.includes(lm?.landmark_type));
            }

            if (mapState.onlyOwned) {
                landmarks = landmarks?.filter(lm => landmarkOwnedByUser(lm));
            }
        }

        return landmarks
    }

    /**
     * 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) => {
        if (mapState.selectedLandmarkId == landmark.id) {
            mapState.toggleLmDetails(true)
        }
        else {
            mapState.setSelectedLandmarkId(landmark.id);
        }
    }

    /**
 * 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 (this issue shows up in many other parts of the app where a modal is toggled by a boolean, and is solved in the same way).
 */
    const promptAddLandmark = async (longitude?: number, latitude?: number, floor?: number) => {
        console.log('[Map]: Opening add landmark panel...')
        addLandmarkStore.stageNewLandmarkWithLocation({latitude: latitude, longitude: longitude}, floor)
        mapState.toggleLmAdd(true)
        mapState.toggleLmDetails(false)
    }


    return (
        <View style={{ flex: 1 }}>
            <MapStackNavigator.Navigator screenOptions={{ headerShown: false }} initialRouteName="Outdoor">
                <MapStackNavigator.Screen name="Outdoor" >
                    {({ navigation }) =>
                        <OutdoorMap
                            authNavIndex={navigationState.index}
                            promptAddLandmark={promptAddLandmark}
                            toggleLmAdd={mapState.toggleLmAdd}
                            toggleLmDetails={mapState.toggleLmDetails}
                            applyFilters={applyFilters}
                            focusLandmark={focusLandmark}
                            route={authRoute}
                            mapNavigation={navigation}
                            authNavigation={authNavigation}
                            landmarks={landmarksQuery?.data}
                            selectedLandmarkId={mapState.selectedLandmarkId}
                            setSelectedLandmarkId={mapState.setSelectedLandmarkId} />}
                </MapStackNavigator.Screen>

                <MapStackNavigator.Screen name="Indoor" >
                    {({ navigation }) =>
                        <IndoorMap
                            navigation={navigation}
                            landmarks={landmarksQuery?.data}
                            promptAddLandmark={promptAddLandmark}
                            focusLandmark={focusLandmark}
                            applyFilter={applyFilters}
                        />}
                </MapStackNavigator.Screen>

            </MapStackNavigator.Navigator>



            {/* Filter chips and button*/}
            {!mapState.filterVisible && currentRoute == 'Indoor' ?
                <View style={{ top: 60, right: 7.5, position: 'absolute', flexDirection: "row-reverse", justifyContent: 'flex-end' }}>
                    <IconButton size={16} color={colors.red} style={[mapStyles.filterButtonIndoor]} icon="filter" onPress={() => mapState.toggleFilter(true)} />
                    <ScrollView horizontal={true} contentContainerStyle={{ alignItems: 'center' }} style={{ marginHorizontal: 10, flexDirection: 'row' }}>
                        {mapState.onlyOwned ? <Chip avatar={(<FontAwesome name="user" size={20} color='gray' style={{ textAlign: 'center', textAlignVertical: 'center' }} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginRight: 5, marginLeft: 10 }} onClose={() => mapState.toggleOnlyOwned(false)}>My landmarks</Chip> : null}
                        {mapState.lmFilteredTypes.map((type, i) => {
                            return (
                                <Chip key={i} avatar={(<Image style={{ height: 22, width: 17 }} source={lmTypes[type].image} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginHorizontal: 5, justifyContent: 'center' }} onClose={() => mapState.setLmTypeFilter(mapState.lmFilteredTypes.filter(t => t !== type))}>{lmTypes[type].label}</Chip>
                            )
                        })}
                        {mapState.minLmRating > 0 ? <Chip avatar={(<FontAwesome name="star" size={20} color='gray' style={{ textAlign: 'center', textAlignVertical: 'center' }} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginLeft: 5, marginRight: 10 }} onClose={() => mapState.setMinLmRating(0)}>Minimum rating: {mapState.minLmRating}</Chip> : null}
                    </ScrollView>
                </View>
                :
                <View style={{ top: 10, marginLeft: 40, marginRight: 20, position: 'absolute', flexDirection: "row-reverse", justifyContent: 'flex-end' }}>
                    <IconButton size={20} color={colors.red} style={[mapStyles.filterButtonOutdoor]} icon="filter" onPress={() => mapState.toggleFilter(true)} />
                    <ScrollView horizontal={true} contentContainerStyle={{ alignItems: 'center' }} style={{ marginHorizontal: 10, flexDirection: 'row' }}>
                        {mapState.onlyOwned ? <Chip avatar={(<FontAwesome name="user" size={20} color='gray' style={{ textAlign: 'center', textAlignVertical: 'center' }} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginRight: 5, marginLeft: 10 }} onClose={() => mapState.toggleOnlyOwned(false)}>My landmarks</Chip> : null}
                        {mapState.lmFilteredTypes.map((type, i) => {
                            return (
                                <Chip key={i} avatar={(<Image style={{ height: 22, width: 17 }} source={lmTypes[type].image} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginHorizontal: 5, justifyContent: 'center' }} onClose={() => mapState.setLmTypeFilter(mapState.lmFilteredTypes.filter(t => t !== type))}>{lmTypes[type].label}</Chip>
                            )
                        })}
                        {mapState.minLmRating > 0 ? <Chip avatar={(<FontAwesome name="star" size={20} color='gray' style={{ textAlign: 'center', textAlignVertical: 'center' }} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginLeft: 5, marginRight: 10 }} onClose={() => mapState.setMinLmRating(0)}>Minimum rating: {mapState.minLmRating}</Chip> : null}
                    </ScrollView>
                </View>
            }

            {/* Create Hamburger icon */}
            {currentRoute == 'Indoor' ?
                <View style={{ top: 100, right: 7.5, position: 'absolute', }}>
                    <Menu
                        visible={visible}
                        anchor={<IconButton size={16} color={colors.red} style={[mapStyles.filterButtonIndoor]} icon="bars" onPress={() => setVisible(true)} />}
                        onRequestClose={() => setVisible(false)}
                    >
                        <MenuItem onPress={() => {
                            setVisible(false)
                            navigate("Outdoor")
                            // Alert.alert("Cameron Library")
                        }}>Go Back Outdoors</MenuItem>

                        <MenuItem onPress={() => {
                            setVisible(false)
                            Linking.openURL('https://www.ualberta.ca/facilities-operations/portfolio/emergency-management-office/emergency-procedures/alarms-evacuation.html')
                            // Alert.alert("Cameron Library")
                        }}>Emergency Procedures</MenuItem>

                        <MenuItem onPress={() => {
                            setVisible(false)
                            Linking.openURL('https://www.library.ualberta.ca/')
                            // Alert.alert("Cameron Library")
                        }}>Resources</MenuItem>

                    </Menu>
                </View>
                :
                <View style={{ top: 60, right: 20, position: 'absolute', }}>
                    <Menu
                        visible={visible}
                                                                                                        // either "bars" or "list"  
                        anchor={<IconButton size={20} color={colors.red} style={[mapStyles.filterButtonOutdoor]} icon="bars" onPress={() => setVisible(true)} />}
                        onRequestClose={() => setVisible(false)}
                    >
                        <MenuItem disabled={true} disabledTextColor='black' style={{ alignItems: 'center', borderColor: 'black', borderBottomWidth: 1, marginHorizontal: 10, opacity: .7 }}>
                            <Text>Indoor buildings</Text>
                        </MenuItem>
                        
                        <MenuItem onPress={() => {
                            setVisible(false)
                            navigate("Indoor")
                            // Alert.alert("Cameron Library")
                        }}>Cameron</MenuItem>

                        <MenuDivider />
                        <MenuItem disabled>More indoor maps on the way!</MenuItem>

                    </Menu>

                </View>
            }

            <AddLandmarkPanel setVisible={mapState.toggleLmAdd} visible={mapState.lmAddVisible} />
            <LandmarkDetails
                authNavigation={authNavigation}
                visible={mapState.lmDetailsVisible}
                toggleLmDetails={mapState.toggleLmDetails}
                setLandmark={mapState.setSelectedLandmarkId}
                toggleDetailsPanel={mapState.toggleLmDetails}
                setEditing={mapState.toggleLmDetailsEditing}
                editingEnabled={mapState.lmDetailsEditing}
                landmarkId={mapState.selectedLandmarkId} />
            <FilterPanel
                visible={mapState.filterVisible}
                toggleOnlyOwned={mapState.toggleOnlyOwned}
                onlyOwned={mapState.onlyOwned} toggleFilter={mapState.toggleFilter}
                setMinLmRating={mapState.setMinLmRating}
                setLmFilteredTypes={mapState.setLmTypeFilter}
                lmFilteredTypes={mapState.lmFilteredTypes}
                minLmRating={mapState.minLmRating} />
        </View>
    )
}

export default observer(MapNavigator)