import { FontAwesome } from "@expo/vector-icons";
import React, { memo, useEffect, useRef, useState } from "react";
import { ActivityIndicator, Alert, Dimensions, FlatList, Image, Keyboard, Platform, SafeAreaView, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
import { ScrollView } from "react-native-gesture-handler";
import Modal from 'react-native-modal';
import { LMComment, useComments } from "../../../../hooks/useComments";
import { Landmark, LMPhoto, useLandmarks } from "../../../../hooks/useLandmarks";
import { useProfile } from "../../../../hooks/useProfile";
import { authStore } from "../../../../stores/AuthStore";
import { colors } from "../../../../utils/GlobalUtils";
import { IconButton, PrimaryButton } from "../../../Buttons";
import { DetailsBody } from "./DetailsBody";
import { DetailsHeader } from "./DetailsHeader";

/**
 * Props for the {@link LandmarkDetails} component.
 */
export interface LandmarkDetailsProps {
    /**
     * The {@link Landmark} object being displayed/edited in the {@link LandmarkDetails} modal. 
     */
    landmarkId: string | undefined
    /**
     * The state setter for {@link Landmark} object being displayed/edited in the {@link LandmarkDetails} modal. 
     */
    setLandmark: (landmark: string) => void; 
    /**
     * A callback passed from the parent {@link Map} that toggles the visibility of the {@link LandmarkDetails} modal.
     */
    toggleDetailsPanel: (state: boolean) => void;
    /**
     * A callback passed from the parent {@link Map} that toggles the ability to edit the {@link Landmark} in {@link LandmarkDetails} modal.
     */
    setEditing: (state: boolean) => void;
    /**
     * A flag that determines whether the properties of the {@link Landmark} displayed in the {@link LandmarkDetails} modal can be edited
     */
    editingEnabled: boolean,
    visible: boolean,
    toggleLmDetails: (state: boolean) => void
}

/**
 * Component that renders the details of a selected {@link Landmark} and allows the user to edit those details. Contained within a [react-native-modal]{@link https://github.com/react-native-modal/react-native-modal}.
 * @component
 * @category Map
 */
const LandmarkDetails: React.FC<LandmarkDetailsProps> = ({landmarkId, setLandmark, toggleDetailsPanel, setEditing, editingEnabled, visible, toggleLmDetails}) => {
    // /**
    //  * Holds the state of the {@link Landmark} being displayed.
    //  */
    // const selectedLandmarkState = undefined;
    // const [selectedLandmark, setLandmark] = useState<Landmark | undefined>(selectedLandmarkState);
    /**
     * Holds state of a {@link Landmark} object parallel to {@linkcode selectedLandmarkState} that is manipulated when {@linkcode editingEnabled} is true.
     */
    const [updatedLandmark, setUpdatedLandmark] = useState<Landmark | undefined>(undefined);
    /**
     * Holds text of the current {@link LMComment} being added to this {@link Landmark}.
     */
     const [newCommentId, setNewComment] = useState<string>("");
    /**
     * Holds id of the focused {@link LMComment} in the comment list.
     */
    const [focusedCommentId, setFocusedComment] = useState<string>("");
    /**
     * Holds state of the {@link LMComment} being currently edited.
     */
     const [commentBeingEdited, setCommentBeingEdited] = useState<LMComment | undefined>(undefined);

    /**
     * Flag that tracks if the keyboard is open
     */
    const [keyboardOpened, setKeyboardOpened] = useState<boolean>(false);  
    
    /**
     * State that tracks the index of the currently selected photo, if any are selected
     */
    const [selectedImage, setSelectedImage] = useState<number>(-1)

    const { 
        updateLandmark, updateLandmarkStatus, resetUpdateLm,
        rateLandmarkAsync, rateLandmarkStatus, resetRateLandmark, rating,
        deleteLandmark, deleteLandmarkStatus, resetDeleteLm,
        landmarkRatedByUser, refetchCheckIfRatedByUser,
        landmark, getLandmarkStatus, refetchLandmark,
        deletePhoto, deletePhotoStatus, resetDeletePhoto 
    } = useLandmarks({
        landmarkId: landmarkId,
        userLMPairing: {userId: authStore.userId, landmarkId: landmarkId}
    });

    const {
        comments, 
        addCommentAsync, addCommentStatus, resetAddComment,
        updateCommentAsync, updateCommentStatus, resetUpdateComment,
        deleteCommentAsync, deleteCommentStatus, resetDeleteComment,
    } = useComments(landmarkId)
    const { profile } = useProfile(authStore.userId)

    /**
     * Holds a reference to the Flatlist containing the comments.
     */
    const commentListRef = useRef<FlatList>();
    /**
     * Holds a reference to the text input for posting a new comment
     */
    const commentTextInputRef = useRef<TextInput>();

    useEffect(() => {
        /**
         * Resets the {@linkcode rateLandmark} mutation on successful update.
         * Embedded in a useEffect that listens to the {@linkcode rateLandmarkStatus} value from the {@link useLandmarks} hook.
         * @memberOf LandmarkDetails
         */
         const resetUpdateLandmark = async () => {
            if (rateLandmarkStatus == 'success') {
                resetRateLandmark();
                await refetchLandmark()
            }

            if (updateLandmarkStatus == 'success') {
                resetUpdateLm();
                await refetchLandmark()
            }
        }
        resetUpdateLandmark();
    }, [rateLandmarkStatus, updateLandmarkStatus]);

    useEffect(() => {
        /**
         * Resets the {@linkcode updateComment} mutation on successful update.
         * Embedded in a useEffect that listens to the {@linkcode updateCommentStatus} value from the {@link useComments} hook.
         * @memberOf LandmarkDetails
         */
         const resetUpdateComment = () => {
            if (updateCommentStatus == 'success') {
                commentListRef.current?.scrollToItem({animated: true, item: commentBeingEdited});
                setCommentBeingEdited(undefined)
                Keyboard.dismiss();
            }
        }
        resetUpdateComment();
    }, [updateCommentStatus]);

    useEffect(() => {
        /**
         * Resets the {@linkcode deleteLandmark} mutation on successful delete.
         * Embedded in a useEffect that listens to the {@linkcode deleteLandmarkStatus} value from the {@link useLandmarks} hook.
         * @memberOf LandmarkDetails
         */
        const resetDeleteLMOnSuccess = () => {
            if (deleteLandmarkStatus == 'success') {
                resetDeleteLm();
            }
        }
        resetDeleteLMOnSuccess();
    }, [deleteLandmarkStatus]);

    useEffect(() => {
        /**
         * Resets the {@link addCommentAsync} mutation on successful add.
         * Embedded in a useEffect that listens to the {@link addCommentAsync} value from the {@link useComment} hook.
         * @memberOf LandmarkDetailsLandmark
         */
        const resetAddCommentOnSuccess = () => {
            if (addCommentStatus == 'success') {
                resetAddComment();
            }
            setNewComment('')
            commentListRef.current?.scrollToIndex({animated: true, index: 0});
            Keyboard.dismiss();
        }
        resetAddCommentOnSuccess();
    }, [addCommentStatus]);

    useEffect(() => {
        /**
         * Clears selected comment when {@linkcode newCommentId} state changes.
         * @memberOf LandmarkDetails
         */
        const clearSelectedOnNewCommentChange = () => {
            setFocusedComment('')
        }
        clearSelectedOnNewCommentChange();
    }, [newCommentId]);

    useEffect(() => {
        /**
         * Refetch the user's rate pairing for the current landmark when {@linkcode landmark} state changes.
         * @memberOf LandmarkDetails
         */
        const refetechRateStatus = async () => {
            await refetchCheckIfRatedByUser();
        }
        refetechRateStatus();
    }, [landmark]);

    /**
     * Toggles whether or not the {@linkcode selectedLandmark} can be edited through the {@linkcode editingEnabled} prop.
     */
    const toggleEditing = (editingState: boolean) => {
        if (editingState) { setUpdatedLandmark(landmark); }
        else { setUpdatedLandmark(undefined); }
        setEditing(editingState);   
    }

    /**
     * Calls the {@linkcode updateLandmark} mutation from the {@link useLandmarks} hook and closes the modal once finished.
     */
    const editLandmark = async () => {
        if (updatedLandmark) {
            await updateLandmark(updatedLandmark);       
        }
        
        setEditing(false);
    }

    /**
     * Calls the {@linkcode rateLandmarkAsunc} mutation from the {@link useLandmarks} hook. If 1, the landmark will be upvoted. If -1, it will be downvoted
     */
     const rateLandmark = async (rating: 1 | -1) => {
        if (landmark) {
            await rateLandmarkAsync({id: landmark.id, rating: rating});
        }
    }

    /**
     * Calls the {@linkcode deleteLandmark} mutation from the {@link useLandmarks} hook and closes the modal once finished.
     */
    const removeLandmark = async () => {
        await deleteLandmark(landmark?.id);   
        toggleDetailsPanel(false);
    }

    /**
     * Calls the {@linkcode addComment} mutation from the {@link useComments} hook.
     */
    const addComment = async () => {
        if (newCommentId) {
            await addCommentAsync({
                edited: false,
                content: newCommentId,
                landmark: landmark?.id,
                poster: authStore.userId,
                poster_name: profile.username,
                id: ''
            });
        }
    }

    /**
     * Set a comment to be focused in the comment box. It will expand and show delete and edit controls for that comment. 
     * If the comment id given is already selected, the comment will be unselected
     */
    const focusComment = (id: string) => {
        if (focusedCommentId == id) {
            setFocusedComment("");
        }
        else {
            setFocusedComment(id);
        }
    }

    /**
     * Set a comment to be the comment currently edited. 
     */
    const startEditingComment = (comment: LMComment) => {
        setCommentBeingEdited(comment);
        commentTextInputRef.current.focus();
    }

    /**
     * Calls the {@linkcode editComment} mutation from the {@link useComments} hook.
     */
    const editComment = async (comment: LMComment) => {
        await updateCommentAsync(comment);
    }

    /**
     * Calls the {@linkcode deleteComment} mutation from the {@link useComments} hook.
     */
    const deleteComment = async (id: string) => {
        deleteCommentAsync(id);
    }

    const getWindowWidth = () => {
        return Dimensions.get('window').width
    }

    /**
     * Prompts user for a confirmation to delete the photo that they just tried to delete
     */
    const tryDeletePhoto = (photoId: string) => {
        Alert.alert(
            'Confirm photo removal', 
            'Are you sure you want to delete this photo?', 
            [
                {text: 'Yes', 
                onPress: async () => {
                    await deletePhoto(photoId)
                    setSelectedImage(-1)
                    await refetchLandmark()
                }},
                {text: 'No'} 
            ])
    }

    /**
     * Returns a height for the modal depending on if an image is maximzed, if the keyboard is opened, and if the current landmark has photos associated with it
     */
    const determineModalHeight = () => {
        if (selectedImage > -1) 
            return Dimensions.get("window").height 
        else if (keyboardOpened && Platform.OS == 'android' || (profile?.id != landmark?.user && landmark?.photos?.length == 0))
            return Dimensions.get("window").height * .5
        else if (landmark?.photos?.length > 0) 
            return Dimensions.get("window").height * .9 
        else
            return Dimensions.get("window").height * .7
    }

    return (
        <Modal 
            useNativeDriver={true}
            useNativeDriverForBackdrop={true}
            avoidKeyboard={false}
            onBackdropPress={() => {
                if (editingEnabled) {
                    Keyboard.dismiss();
                } else {
                    toggleLmDetails(false)   
                }
            }}
            style={{justifyContent: "flex-end", height: '100%', margin: 0}}
            isVisible={visible}>
            <SafeAreaView 
                style={[styles.container, {height: determineModalHeight()}]}>
                {selectedImage > -1 ?
                <View style={{ padding: 14}}>
                    <View style={{justifyContent: 'space-between', flexDirection: 'row'}}>
                        <TouchableOpacity onPress={() => setSelectedImage(-1)}>
                            <>
                                <Text style={{color: 'white', fontSize:20}}><FontAwesome name="arrow-left" color="white" size={20}/> Back</Text>
                            </>
                        </TouchableOpacity>
                        <IconButton style={{alignSelf: 'flex-end', marginBottom: 20}} icon="trash" color="white" size={25} onPress={() => tryDeletePhoto(landmark?.photos[selectedImage].id)}/>
                    </View>
                    <ScrollView style={{width: '100%', }}>
                        <Image style={{resizeMode: 'contain', alignSelf: 'center', height: Dimensions.get('window').height * .9, width: getWindowWidth()}} source={{uri: 'data:image/png;base64,' + landmark?.photos[selectedImage].image_b64}}/> 
                    </ScrollView>
                </View>
                :
                (getLandmarkStatus == 'success' || getLandmarkStatus == 'idle') && 
                updateLandmarkStatus == "idle" || updateLandmarkStatus == "success" && 
                deleteLandmarkStatus == "idle" || deleteLandmarkStatus == "success" ?
                <>
                <DetailsHeader
                    toggleDetailsPanel={toggleDetailsPanel}
                    landmark={landmark}
                    landmarkRatedByUser={landmarkRatedByUser}
                    editLandmark={editLandmark}
                    editingEnabled={editingEnabled}
                    toggleEditing={toggleEditing}
                    rateLandmark={rateLandmark}
                    removeLandmark={removeLandmark}
                    updatedLandmark={updatedLandmark}
                    profile={profile} />
                <DetailsBody 
                    profileId={profile?.id}
                    setKeyboardOpened={setKeyboardOpened}
                    keyboardOpened={keyboardOpened}
                    setSelectedImage={setSelectedImage}
                    landmark={landmark}
                    updatedLandmark={updatedLandmark}
                    commentListRef={commentListRef}
                    commentTextInputRef={commentTextInputRef}
                    commentBeingEdited={commentBeingEdited}
                    comments={comments}
                    addComment={addComment}
                    setCommentBeingEdited={setCommentBeingEdited}
                    newCommentId={newCommentId}
                    editComment={editComment}
                    focusComment={focusComment}
                    deleteComment={deleteComment}
                    setNewComment={setNewComment}
                    focusedCommentId={focusedCommentId}
                    startEditingComment={startEditingComment}
                    editingEnabled={editingEnabled}
                    setUpdatedLandmark={setUpdatedLandmark}
                    tryDeletePhoto={tryDeletePhoto}
                    deletePhotoStatus={deletePhotoStatus}
                    toggleLmDetails={toggleLmDetails}/>
                </> :
                <View style={{height: '100%', justifyContent: "space-evenly", alignItems: "center", marginHorizontal: 20}}>
                    <Text style={{color: 'white', fontSize: 20}}>{
                        getLandmarkStatus == 'loading' ? "Loading landmark..." : 
                        getLandmarkStatus == 'error' ? "Something went wrong trying to load the landmark" :
                        deleteLandmarkStatus == 'loading' ? "Deleting landmark..." : 
                        deleteLandmarkStatus == 'error' ? "Something went wrong trying to delete the landmark" :
                        updateLandmarkStatus == 'loading' ? "Updating landmark..." : 
                        updateLandmarkStatus == 'error' ? "Something went wrong trying to update the landmark" :
                        addCommentStatus == 'loading' ? "Adding comment..." : 
                        addCommentStatus == 'error' ? "Something went wrong trying to add the comment" : 
                        updateCommentStatus == 'loading' ? "Updating comment..." : 
                        updateCommentStatus == 'error' ? "Something went wrong trying to update the comment" :  
                        deleteCommentStatus == 'loading' ? "Deleting comment..." : 
                        deleteCommentStatus == 'error' ? "Something went wrong trying to delete the comment" : null} 
                    </Text>
                    {
                        deleteLandmarkStatus == 'loading' || updateLandmarkStatus == 'loading' || getLandmarkStatus == "loading" ? <ActivityIndicator color='white' size="large"/> :
                        deleteLandmarkStatus == 'error' || updateLandmarkStatus == 'error' || getLandmarkStatus == "error" ? <PrimaryButton text="Okay" style={{borderColor: 'white', borderWidth: 1}} onPress={() => refetchLandmark()} /> : null
                    }
                </View>}
            </SafeAreaView>
        </Modal>
    )
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: colors.red,
    },
    detailsContainer: {
        flex: 1,
        marginHorizontal: 20
    },

    commentContainer: {
        flex: 5,
        marginBottom: 40,
    },
    title: {

    },
    input: {
        padding: 5,
        color: 'black'
    }
})

export default memo(LandmarkDetails);