"use client";

import { useState } from 'react';
import { toast } from 'react-toastify';
import Swal from 'sweetalert2';
import { AlertTriangle, Info } from "lucide-react";
import { IconSpinner } from '@/app/components/ui/icons';
import { useSession } from "next-auth/react";

export default function QueryDocumentUpload() {
    const [files, setFiles] = useState<File[]>([]);
    const [displayName, setDisplayName] = useState('');
    const [description, setDescription] = useState('');
    const [displayNameError, setDisplayNameError] = useState(false);
    const [descriptionError, setDescriptionError] = useState(false);
    const [fileError, setFileError] = useState(false);
    const [fileErrorMsg, setFileErrorMsg] = useState('');
    const [isLoading, setisLoading] = useState(false);
    const indexerApi = process.env.NEXT_PUBLIC_INDEXER_API;
    const { data: session } = useSession();
    const supabaseAccessToken = session?.supabaseAccessToken;
    // NOTE: allowedTypes is an array of allowed MIME types for file uploads
    // The allowedTypesString is a string of allowed file extensions for the file input
    // Both must be kept in sync to ensure that the file input only accepts the allowed file types
    const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'text/plain', 'application/json'];
    const allowedTypesString = ".pdf,.doc,.docx,.xls,xlsx,.txt,.json";

    const MAX_FILES = 15; // Maximum number of files allowed
    const MAX_TOTAL_SIZE_MB = 60; // Maximum total size allowed in MB (60 MB)
    const MAX_TOTAL_SIZE = MAX_TOTAL_SIZE_MB * 1024 * 1024; // Maximum total size allowed in bytes (60 MB in bytes)
    // The total size of all selected files should not exceed this value

    const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setFileError(false);
        const selectedFiles = event.target.files;
        if (selectedFiles) {
            const fileList = Array.from(selectedFiles);

            // Check if the total number of files exceeds the maximum allowed
            if (fileList.length > MAX_FILES) {
                // Show toast notification
                toast.error(`You can only upload a maximum of ${MAX_FILES} files.`, {
                    position: "top-right",
                    autoClose: 5000,
                    hideProgressBar: false,
                    closeOnClick: true,
                    pauseOnHover: true,
                });
                setFileError(true);
                setFileErrorMsg(`You can only upload a maximum of ${MAX_FILES} files.`);
                return;
            }

            // Calculate the total size of selected files
            const totalSize = fileList.reduce((acc, file) => acc + file.size, 0);

            // Check if the total size exceeds the maximum allowed
            if (totalSize > MAX_TOTAL_SIZE) {
                // Show toast notification
                toast.error(`Total size of selected files exceeds the maximum allowed (${MAX_TOTAL_SIZE_MB} MB).`, {
                    position: "top-right",
                });
                setFileError(true);
                setFileErrorMsg(`Total size of selected files exceeds the maximum allowed (${MAX_TOTAL_SIZE_MB} MB).`);
                return;
            }

            // Check if the file types are allowed
            const invalidFiles = fileList.filter(file => !allowedTypes.includes(file.type));
            if (invalidFiles.length) {
                // Show toast notification
                toast.error(`Invalid file type(s) selected!`, {
                    position: "top-right",
                });
                setFileError(true);
                setFileErrorMsg(`Only ${allowedTypesString} file type(s) allowed!`);
                return;
            }

            // Update the state with the selected files
            setFiles(fileList);
        }
    };

    const handleDescriptionChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setDescription(event.target.value);
        setDescriptionError(false);
    };

    const handleDisplayNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setDisplayName(event.target.value);
        setDisplayNameError(false);
    };

    const handleSubmit = (event: React.FormEvent) => {
        let createdCollectionId = '';
        event.preventDefault();
        // Perform validation and submit logic here
        console.log("Display Name:", displayName);
        console.log("Description:", description);
        console.log("Files:", files);
        // Ensure that the required fields are not empty
        if (!displayName.trim()) {
            setDisplayNameError(true);
            console.log("Display Name is required!");
        }
        if (!description.trim()) {
            setDescriptionError(true);
            console.log("Description is required!");
        }
        if (!files.length) {
            setFileError(true);
            setFileErrorMsg("Please select a file to upload!");
            console.log("Please select a file to upload!");
        }
        if (!displayName.trim() || !description.trim() || !files.length) {
            // Show toast notification
            toast.error("Please fill in all required fields!", {
                position: "top-right",
                closeOnClick: true,
            });
        }
        else {
            setisLoading(true);
            // Show confirmation dialog
            Swal.fire({
                title: 'Are you sure?',
                text: "You are about to upload and index your documents. Ensure that there are no sensitive/secret documents! Do you want to proceed?",
                icon: 'warning',
                showCancelButton: true,
                confirmButtonColor: '#4caf50',
                cancelButtonColor: '#b91c1c',
                confirmButtonText: 'Yes',
                cancelButtonText: 'No',
            }).then((result) => {
                if (result.isConfirmed) {
                    // Perform the upload and indexing logic
                    console.log("Uploading and indexing documents...");
                    // Make a POST request to the API with the form data to save to the database
                    fetch('/api/user/collections', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify({
                            display_name: displayName,
                            description: description,
                        }),
                    })
                        .then(async response => {
                            if (response.ok) {
                                // Get the response data
                                const data = await response.json();
                                console.log('Insert New Collection Results:', data);
                                createdCollectionId = await data.collectionId; // ensure that the collection_id is returned
                                console.log('Created Collection ID:', createdCollectionId);
                                // Show success dialog
                                Swal.fire({
                                    title: 'Success!',
                                    text: 'Documents uploaded successfully! The documents will be indexed shortly. Do not leave this page until the indexing is completed!',
                                    icon: 'success',
                                    confirmButtonColor: '#4caf50',
                                });
                                // Show toast loading notification
                                const toastId = toast.loading('Uploading and Indexing Documents...');
                                // Create a new FormData object
                                const formData = new FormData();
                                // Append the collection_id to the FormData object
                                formData.append('collection_id', createdCollectionId);
                                // Append each file to the FormData object
                                files.forEach((file, index) => {
                                    formData.append('files', file);
                                });
                                // Make a POST request to the Backend Indexer API with the files data to upload and index
                                fetch(`${indexerApi}`, {
                                    method: 'POST',
                                    headers: {
                                        // Add the access token to the request headers
                                        'Authorization': `Bearer ${supabaseAccessToken}`,
                                    },
                                    body: formData,
                                })
                                    .then(async response => {
                                        if (response.ok) {
                                            // Get the response data
                                            const data = await response.json();
                                            console.log('Indexer Results:', data);
                                            setisLoading(false);
                                            // Update toast notification
                                            toast.update(toastId, {
                                                render: 'Documents uploaded and indexed successfully! 🎉',
                                                type: 'success',
                                                className: 'rotateY animated',
                                                autoClose: 5000,
                                                closeButton: true,
                                                isLoading: false
                                            });
                                            // Reset the form fields
                                            setDisplayName('');
                                            setDescription('');
                                            setFiles([]);
                                        } else {
                                            const data = await response.json();
                                            // Log to console
                                            console.error('Error uploading and indexing documents:', data.error);
                                            setisLoading(false);
                                            // Update toast notification
                                            toast.update(toastId, {
                                                render: 'Failed to upload and index documents! 😢 (Check Console for details)',
                                                type: 'error',
                                                className: 'rotateY animated',
                                                autoClose: 5000,
                                                closeButton: true,
                                                isLoading: false
                                            });
                                            // Delete the previously inserted collection from the database
                                            fetch('/api/user/collections', {
                                                method: 'DELETE',
                                                headers: {
                                                    'Content-Type': 'application/json',
                                                },
                                                body: JSON.stringify({
                                                    collection_id: createdCollectionId,
                                                    delete_vecs: false,
                                                }),
                                            })
                                                .then(async response => {
                                                    if (response.ok) {
                                                        // Get the response data
                                                        const data = await response.json();
                                                        console.log('Delete Collection Results:', data);
                                                    } else {
                                                        const data = await response.json();
                                                        // Log to console
                                                        console.error('Error deleting collection:', data.error);
                                                    }
                                                });
                                        }
                                    })
                                    .catch(error => {
                                        console.error('Error uploading and indexing documents:', error);
                                        setisLoading(false);
                                        // Update toast notification
                                        toast.update(toastId, {
                                            render: 'Failed to upload and index documents! 😢 (Check Console for details)',
                                            type: 'error',
                                            className: 'rotateY animated',
                                            autoClose: 5000,
                                            closeButton: true,
                                            isLoading: false
                                        });
                                        // Delete the previously inserted collection from the database
                                        fetch('/api/user/collections', {
                                            method: 'DELETE',
                                            headers: {
                                                'Content-Type': 'application/json',
                                            },
                                            body: JSON.stringify({
                                                collection_id: createdCollectionId,
                                                delete_vecs: false,
                                            }),
                                        })
                                            .then(async response => {
                                                if (response.ok) {
                                                    // Get the response data
                                                    const data = await response.json();
                                                    console.log('Delete Collection Results:', data);
                                                } else {
                                                    const data = await response.json();
                                                    // Log to console
                                                    console.error('Error deleting collection:', data.error);
                                                }
                                            });
                                    });
                            } else {
                                const data = await response.json();
                                // Log to console
                                console.error('Error uploading and indexing documents:', data.error);
                                // Show error dialog
                                Swal.fire({
                                    title: 'Error!',
                                    text: 'Failed to upload and index documents. Please try again later. (Check Console for more details)',
                                    icon: 'error',
                                    confirmButtonColor: '#4caf50',
                                });
                                setisLoading(false);
                            }
                        })
                        .catch(error => {
                            console.error('Error uploading and indexing documents:', error);
                            // Show error dialog
                            Swal.fire({
                                title: 'Error!',
                                text: 'Failed to upload and index documents. Please try again later. (Check Console for more details)',
                                icon: 'error',
                                confirmButtonColor: '#4caf50',
                            });
                            setisLoading(false);
                        });
                }
                else {
                    setisLoading(false);
                }
            });
        }
    };

    return (
        <div className="w-full rounded-xl bg-white dark:bg-zinc-700/30 dark:from-inherit p-4 shadow-xl">
            <div className="rounded-lg pt-5 pr-10 pl-10 flex h-[50vh] flex-col divide-y overflow-y-auto">
                <form onSubmit={handleSubmit} className="flex flex-col w-full justify-center gap-4">
                    <h2 className="text-lg text-center font-semibold mb-4">Upload & Index Your Own Document Set:</h2>
                    {/* Warning Banner */}
                    <div className="flex flex-col bg-red-100 border border-orange-400 text-orange-600 px-4 py-3 rounded text-center items-center" role="alert">
                        <AlertTriangle />
                        <div className="flex text-center items-center font-bold">
                            WARNING
                        </div>
                        <div className="flex">Smart Retrieval is still in the demo stage, avoid uploading sensitive/secret documents.</div>
                    </div>
                    <div className={`flex flex-col ${displayNameError ? 'has-error' : ''}`}>
                        <label htmlFor="displayName" title='Display Name' className='mb-2'>Display Name:</label>
                        <input
                            type="text"
                            id="displayName"
                            title='Display Name'
                            value={displayName}
                            onChange={handleDisplayNameChange}
                            className={`h-10 rounded-lg w-full border px-2 bg-gray-300 dark:bg-zinc-700/65 ${displayNameError ? 'border-red-500 ' : ''}`}
                        />
                        {displayNameError && <p className="text-red-500 text-sm pl-1 pt-1">Display Name is required!</p>}
                    </div>
                    <div className={`flex flex-col ${descriptionError ? 'has-error' : ''}`}>
                        <label htmlFor="collectionName" title='Description' className='mb-2'>Description:</label>
                        <input
                            type="text"
                            id="description"
                            title='Description'
                            value={description}
                            onChange={handleDescriptionChange}
                            className={`h-10 rounded-lg w-full border px-2 bg-gray-300 dark:bg-zinc-700/65 ${descriptionError ? 'border-red-500' : ''}`}
                        />
                        {descriptionError && <p className="text-red-500 text-sm pl-1 pt-1">Description is required!</p>}
                    </div>
                    <div className='flex flex-col'>
                        <label htmlFor="fileUpload" title='Select Files' className='mb-2'>
                            Select Files:
                            <span className="text-sm text-gray-500 ml-1">{`(Up to ${MAX_FILES} files, total ${MAX_TOTAL_SIZE_MB} MB)`}</span>
                        </label>
                        <input
                            type="file"
                            id="fileUpload"
                            title='Select Files'
                            multiple
                            accept={allowedTypesString}
                            onChange={handleFileChange}
                            className={`h-12 rounded-lg w-full bg-gray-300 dark:bg-zinc-700/65 border px-2 py-2 ${fileError ? 'border-red-500' : ''}`}
                        />
                        {fileError && <p className="text-red-500 text-sm pl-1 pt-1">{fileErrorMsg}</p>}
                    </div>
                    <div className="flex flex-col gap-4">
                        <button
                            disabled={isLoading}
                            type="submit"
                            title='Submit'
                            className="text-center items-center text-l disabled:bg-orange-400 bg-blue-500 text-white px-6 py-3 rounded-md font-bold transition duration-300 ease-in-out transform hover:scale-105 disabled:hover:scale-100">
                            {isLoading ? <IconSpinner className="animate-spin h-5 w-5 mx-auto" /> : "Submit"}
                        </button>
                    </div>
                </form>
            </div>
        </div>
    );
}