/* 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 { FontAwesome } from "@expo/vector-icons";
import React, { memo, useEffect, useRef, useState } from "react";
import { ScrollView, ActivityIndicator, Alert, Dimensions, FlatList, Image, Keyboard, Platform, SafeAreaView, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
import Modal from 'react-native-modal';
import { LMComment, useAddComment, useDeleteComment, useEditComment, useLandmarkComments } from "../../../../state/external/comments";
import { Landmark, useAddLandmarkPhoto, useDeleteLandmark, useDeleteLandmarkPhoto, useEditLandmark, useLandmark, useRateLandmark } from "../../../../state/external/landmarks";
import { useAuth } from "../../../../state/external/auth-provider";
import { colors } from "../../../../utils/GlobalUtils";
import { IconButton, PrimaryButton } from "../../../Buttons";
import { DetailsBody } from "./DetailsBody";
import { DetailsHeader } from "./DetailsHeader";
import { useOwnedProfile } from "../../../../state/external/profiles";
import { MainTabsNavigationProp } from "../../../../navigation/main-tabs-navigator";

/**
 * 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
    authNavigation: MainTabsNavigationProp
}

/**
 * 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> = ({authNavigation, landmarkId, setLandmark, toggleDetailsPanel, setEditing, editingEnabled, visible, toggleLmDetails}) => {
    const {userId, landmarkOwnedByUser} = useAuth()

    // /**
    //  * 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 [photosBusy, setPhotosBusy] = useState<boolean>(false)
    const [processingPhoto, setProcessingPhoto] = useState<boolean>(false)

    const landmarkQuery = useLandmark(landmarkId)
    const editLandmarkMutation = useEditLandmark()
    const rateLandmarkMutation = useRateLandmark()
    const deleteLandmarkMutation = useDeleteLandmark()
    const addLandmarkPhotoMutation = useAddLandmarkPhoto()
    const deleteLandmarkPhotoMutation = useDeleteLandmarkPhoto()
    
    const commentsQuery = useLandmarkComments(landmarkId)
    const addCommentMutation = useAddComment()
    const editCommentMutation = useEditComment()
    const deleteCommentMutation = useDeleteComment()
    const { profile } = useOwnedProfile()

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

    useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener(
      'keyboardWillShow',
      () => {
        setKeyboardOpened(true); // or some other action
      }
    );
    const keyboardDidHideListener = Keyboard.addListener(
      'keyboardWillHide',
      () => {
        setKeyboardOpened(false); // or some other action
      }
    );

    return () => {
      keyboardDidHideListener.remove();
      keyboardDidShowListener.remove();
    };
  }, []);

    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 (rateLandmarkMutation.isSuccess) {
                rateLandmarkMutation.reset()
                await landmarkQuery.refetch()
            }

            if (editLandmarkMutation.isSuccess) {
                editLandmarkMutation.reset()
                await landmarkQuery.refetch()
            }
        }
        resetUpdateLandmark();
    }, [rateLandmarkMutation.status, editLandmarkMutation.status]);

    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 (editCommentMutation.isSuccess) {
                commentListRef.current?.scrollToItem({animated: true, item: commentBeingEdited});
                setCommentBeingEdited(undefined)
                Keyboard.dismiss();
            }
        }
        resetUpdateComment();
    }, [editCommentMutation.status]);

    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 (deleteLandmarkMutation.isSuccess) {
                deleteLandmarkMutation.reset()
            }

            console.log(deleteLandmarkMutation.status)
        }
        resetDeleteLMOnSuccess();
    }, [deleteLandmarkMutation.status]);

    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 (addCommentMutation.isSuccess) {
                addCommentMutation.reset()
            }
            setNewComment('')
            commentListRef.current?.scrollToIndex({animated: true, index: 0});
            Keyboard.dismiss();
        }
        resetAddCommentOnSuccess();
    }, [addCommentMutation.status]);

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

    /**
     * Calls the {@linkcode updateLandmark} mutation from the {@link useLandmarks} hook and closes the modal once finished.
     */
    const editLandmark = async () => {
        if (updatedLandmark) {
            await editLandmarkMutation.mutateAsync(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 (landmarkQuery?.data?.landmark) {
            await rateLandmarkMutation.mutateAsync({id: landmarkId, rating: rating});
        }
    }

    /**
     * Calls the {@linkcode deleteLandmark} mutation from the {@link useLandmarks} hook and closes the modal once finished.
     */
    const removeLandmark = async () => {
        Alert.alert("Are you sure you want to delete this landmark?", undefined,
      [{ text: "Cancel", }
        ,
      {
        text: "Confirm", onPress: async () => {
            await deleteLandmarkMutation.mutateAsync(landmarkId);   
            toggleDetailsPanel(false);
            Alert.alert("Landmark Deleted", "This landmark has been deleted.");
        }
      }])
    }

    /**
     * Calls the {@linkcode addComment} mutation from the {@link useComments} hook.
     */
    const addComment = async () => {
        if (newCommentId) {
            await addCommentMutation.mutateAsync({
                edited: false,
                content: newCommentId,
                landmark: landmarkId,
                poster: 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 editCommentMutation.mutateAsync(comment);
    }

    /**
     * Calls the {@linkcode deleteComment} mutation from the {@link useComments} hook.
     */
    const deleteComment = async (id: string) => {
        await deleteCommentMutation.mutateAsync(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 () => {
                    setPhotosBusy(true)
                    await deleteLandmarkPhotoMutation.mutateAsync(photoId)
                    setSelectedImage(-1)
                    await landmarkQuery.refetch()
                }},
                {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 || editingEnabled || (!landmarkOwnedByUser(landmarkQuery?.data?.landmark) && landmarkQuery?.data?.landmark?.photos?.length == 0)) {
            return Dimensions.get("window").height * .4
        }
        else if (landmarkQuery?.data?.landmark?.photos?.length > 0) 
            return Dimensions.get("window").height * .9 
        else
            return Dimensions.get("window").height * .6
    }

    return (
        <Modal 
            useNativeDriver={true}
            useNativeDriverForBackdrop={true}
            avoidKeyboard={true}
            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(landmarkQuery?.data?.landmark?.photos[selectedImage].id)}/>
                    </View>
                    <ScrollView style={{width: '100%', }} ref={mainScrollRef}>
                        <Image style={{resizeMode: 'contain', alignSelf: 'center', height: Dimensions.get('window').height * .9, width: getWindowWidth()}} source={{uri: 'data:image/png;base64,' + landmarkQuery?.data?.landmark?.photos[selectedImage].image_b64}}/> 
                    </ScrollView>
                </View>
                :
                (landmarkQuery.isSuccess || landmarkQuery.isIdle) && 
                (editLandmarkMutation.isIdle || editLandmarkMutation.isSuccess) && 
                (deleteLandmarkMutation.isIdle || deleteLandmarkMutation.isSuccess) ?
                <>
                <DetailsHeader
                    authNavigation={authNavigation}
                    toggleLmDetails={toggleLmDetails}
                    ratedByUser={landmarkQuery?.data?.ratedByUser}
                    processingPhoto={processingPhoto}
                    addPhotoStatus={addLandmarkPhotoMutation.status}
                    deletePhotoStatus={deleteLandmarkPhotoMutation.status}
                    toggleDetailsPanel={toggleDetailsPanel}
                    landmark={landmarkQuery?.data?.landmark}
                    editLandmark={editLandmark}
                    editingEnabled={editingEnabled}
                    toggleEditing={setEditing}
                    rateLandmark={rateLandmark}
                    removeLandmark={removeLandmark}
                    updatedLandmark={updatedLandmark}
                    profile={profile} />
                <DetailsBody
                    authNavigation={authNavigation} 
                    setProcessingPhoto={setProcessingPhoto}
                    processingPhoto={processingPhoto}
                    profileId={profile?.id}
                    setKeyboardOpened={setKeyboardOpened}
                    keyboardOpened={keyboardOpened}
                    setSelectedImage={setSelectedImage}
                    landmark={landmarkQuery?.data?.landmark}
                    updatedLandmark={updatedLandmark}
                    commentListRef={commentListRef}
                    commentTextInputRef={commentTextInputRef}
                    commentBeingEdited={commentBeingEdited}
                    comments={commentsQuery?.data}
                    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={deleteLandmarkPhotoMutation.status}
                    toggleLmDetails={toggleLmDetails}
                    addPhoto={addLandmarkPhotoMutation.mutateAsync}
                    addPhotoStatus={addLandmarkPhotoMutation.status}/>
                </> :
                <View style={{height: '100%', justifyContent: "space-evenly", alignItems: "center", marginHorizontal: 20}}>
                    <Text style={{color: 'white', fontSize: 20}}>{
                        landmarkQuery.isLoading ? "Loading landmark..." : 
                        landmarkQuery.isError ? "Something went wrong trying to load the landmark" :
                        deleteLandmarkMutation.isLoading ? "Deleting landmark..." : 
                        deleteLandmarkMutation.isError ? "Something went wrong trying to delete the landmark" :
                        editLandmarkMutation.isLoading ? "Updating landmark..." : 
                        editLandmarkMutation.isError ? "Something went wrong trying to update the landmark" :
                        addCommentMutation.isLoading ? "Adding comment..." : 
                        addCommentMutation.isError ? "Something went wrong trying to add the comment" : 
                        editCommentMutation.isLoading ? "Updating comment..." : 
                        editCommentMutation.isError ? "Something went wrong trying to update the comment" :  
                        deleteCommentMutation.isLoading ? "Deleting comment..." : 
                        deleteCommentMutation.error ? "Something went wrong trying to delete the comment" : null} 
                    </Text>
                    {
                        deleteLandmarkMutation.isLoading || editLandmarkMutation.isLoading || landmarkQuery.isLoading ? <ActivityIndicator color='white' size="large"/> :
                        deleteLandmarkMutation.isError || editCommentMutation.isLoading || landmarkQuery.isError ? <PrimaryButton text="Okay" style={{borderColor: 'white', borderWidth: 1}} onPress={async () => await landmarkQuery.refetch()} /> : 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);