import { useState, useCallback } from 'react';
import { getExtensionWithPeriod } from '../utils/getExtension/getExtension';
import { checkEmpty } from '../utils/checkEmpty/checkEmpty';
import { toast } from '../components/Toastify/Toastify';
const useFileDropzone = (options) => {
    const { accept, multiple, maxSize, maxFiles, onMaxFilesError, onDrop, maxSizeErrorMessage, invalidFileMessage, fileExistMessage, validateMIMEType = false, selectedFile, setSelectedFile, handleReplaceFile = () => { }, showRejectedFileDetails, disabledDragAndDrop, } = options;
    const file = !selectedFile ? [] : [selectedFile];
    const [files, setFiles] = useState({
        accepted: file,
        rejected: [],
    });
    const [isDragActive, setIsDragActive] = useState(false);
    const validateFileMIMEType = (file, extensionWithPeriod) => {
        if (accept.includes(file.type))
            return true;
        // these special types doesn't have MIME type, user can pass . extension and get it validated based on file name extension
        const specialTypes = ['.ipa', '.yml', '.md', '.pem', '.properties'];
        return (specialTypes.includes(extensionWithPeriod) &&
            accept.includes(extensionWithPeriod));
    };
    const validateFile = useCallback((file) => {
        const errors = [];
        if (maxSize && file.size > maxSize) {
            errors.push({
                message: maxSizeErrorMessage
                    ? maxSizeErrorMessage
                    : 'File size exceeds the limit',
                code: 'file-size-exceeded',
            });
        }
        const extensionWithPeriod = getExtensionWithPeriod(file).toLowerCase();
        if (validateMIMEType) {
            if (!validateFileMIMEType(file, extensionWithPeriod)) {
                errors.push({
                    message: invalidFileMessage
                        ? invalidFileMessage
                        : 'Unsupported File Format',
                    code: 'file-invalid-type',
                });
            }
        }
        else if (accept && !accept.includes(extensionWithPeriod)) {
            errors.push({
                message: invalidFileMessage
                    ? invalidFileMessage
                    : 'Unsupported File Format',
                code: 'file-invalid-type',
            });
        }
        const fileExists = files.accepted.some((existingFile) => existingFile.name === file.name &&
            getExtensionWithPeriod(existingFile) ===
                getExtensionWithPeriod(file) &&
            existingFile?.lastModified === file?.lastModified);
        if (fileExists) {
            errors.push({
                message: fileExistMessage ? fileExistMessage : 'File already exists.',
                code: 'file-exists',
            });
        }
        return errors;
    }, [
        accept,
        maxSize,
        files,
        maxSizeErrorMessage,
        invalidFileMessage,
        fileExistMessage,
        validateMIMEType,
    ]);
    const handleRejectedFiles = (rejectedFiles) => {
        if (rejectedFiles.length === 1) {
            if (rejectedFiles[0]?.errors[0]?.code === 'file-exists') {
                toast.error('File already exists');
            }
            else if (rejectedFiles[0]?.errors[0]?.code === 'file-size-exceeded') {
                toast.error('File size exceeds the allowed limit');
            }
            else if (rejectedFiles[0]?.errors[0]?.code === 'file-invalid-type') {
                toast.error('Unsupported file format');
            }
        }
        else {
            let duplicateCount = 0;
            let fileSizeExceedCount = 0;
            let invalidTypeCount = 0;
            rejectedFiles.forEach((rej) => {
                if (rej.errors[0]?.code === 'file-exists') {
                    duplicateCount++;
                }
                else if (rej.errors[0]?.code === 'file-size-exceeded') {
                    fileSizeExceedCount++;
                }
                else if (rej.errors[0]?.code === 'file-invalid-type') {
                    invalidTypeCount++;
                }
            });
            const parts = [];
            if (duplicateCount > 0) {
                parts.push(`${duplicateCount} file${duplicateCount > 1 ? 's' : ''} already exist${duplicateCount > 1 ? '' : 's'}`);
            }
            if (fileSizeExceedCount > 0) {
                parts.push(`${fileSizeExceedCount} file${fileSizeExceedCount > 1 ? 's' : ''} exceed${fileSizeExceedCount > 1 ? '' : 's'} the size limit`);
            }
            if (invalidTypeCount > 0) {
                let typeMessage = invalidTypeCount === 1 ? `file is` : `files are`;
                parts.push(`${invalidTypeCount} ${typeMessage} unsupported`);
            }
            if (parts.length > 0) {
                let message = '';
                if (parts.length === 1) {
                    message = parts[0] ?? '';
                }
                else if (parts.length === 2) {
                    message = parts.join(' and ');
                }
                else {
                    message =
                        parts.slice(0, -1).join(', ') + ' and ' + parts[parts.length - 1];
                }
                toast.error(`${message}.`);
            }
            else {
                toast.error('File rejected.');
            }
        }
    };
    const replaceFile = useCallback((fileToReplace, newFile) => {
        if (handleReplaceFile)
            handleReplaceFile(newFile);
        const errors = validateFile(newFile);
        const isValid = checkEmpty(errors);
        setFiles((prevFiles) => {
            const fileNameMatch = (file) => file.name === fileToReplace.name &&
                file.lastModified === fileToReplace.lastModified;
            // === Handle Accepted Files ===
            const hasSameNameInAccepted = prevFiles.accepted.some(fileNameMatch);
            let updatedAccepted;
            if (isValid) {
                if (hasSameNameInAccepted) {
                    // Replace file with same name
                    updatedAccepted = prevFiles.accepted.map((file) => file.name === fileToReplace.name ? newFile : file);
                }
                else {
                    // Remove old file (by name) and add new one
                    updatedAccepted = [
                        ...prevFiles.accepted.filter((file) => file.name !== fileToReplace.name),
                        newFile,
                    ];
                }
            }
            else {
                // Keep accepted unchanged if invalid
                if (showRejectedFileDetails) {
                    updatedAccepted = prevFiles.accepted;
                }
                else {
                    updatedAccepted = prevFiles.accepted.filter((file) => file.name !== fileToReplace.name);
                }
            }
            // === Handle Rejected Files ===
            const hasSameNameInRejected = prevFiles.rejected.some((rejection) => rejection.file.name === fileToReplace.name);
            let updatedRejected;
            if (!isValid) {
                if (hasSameNameInRejected) {
                    // Replace the rejected file with same name
                    updatedRejected = prevFiles.rejected.map((rejection) => rejection.file.name === fileToReplace.name
                        ? { file: newFile, errors }
                        : rejection);
                }
                else {
                    // Remove the old one (by name) and add new rejected
                    updatedRejected = [
                        ...prevFiles.rejected.filter((rejection) => rejection.file.name !== fileToReplace.name),
                        { file: newFile, errors },
                    ];
                }
            }
            else {
                // Clean up the rejected list if file is now valid
                updatedRejected = prevFiles.rejected.filter((rejection) => rejection.file.name !== fileToReplace.name ||
                    rejection.file.size !== fileToReplace.size ||
                    rejection.file.lastModified !== fileToReplace.lastModified);
            }
            // Update selectedFile if valid
            if (isValid && setSelectedFile) {
                setSelectedFile(updatedAccepted);
            }
            if (!checkEmpty(updatedRejected)) {
                handleRejectedFiles(updatedRejected);
            }
            return {
                accepted: updatedAccepted,
                rejected: [],
            };
        });
    }, [validateFile, setSelectedFile]);
    const handleReplaceClick = useCallback((fileToReplace) => {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = accept.join(',');
        input.onchange = (event) => {
            const newFile = event.target?.files?.[0];
            if (newFile &&
                newFile.name !== fileToReplace.name &&
                !showRejectedFileDetails) {
                replaceFile(fileToReplace, newFile);
            }
            else if (newFile && showRejectedFileDetails) {
                replaceFile(fileToReplace, newFile);
            }
        };
        input.click();
    }, [accept, replaceFile]);
    const removeFile = useCallback((fileToRemove) => {
        setFiles((prevFiles) => ({
            accepted: prevFiles.accepted.filter((file) => file !== fileToRemove),
            rejected: prevFiles.rejected.filter((rejection) => rejection.file !== fileToRemove),
        }));
    }, []);
    const handleRemoveClick = useCallback((file) => {
        removeFile(file);
    }, [removeFile]);
    const handleDrop = useCallback((event) => {
        if (disabledDragAndDrop && 'dataTransfer' in event) {
            event.preventDefault();
            event.stopPropagation();
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        setIsDragActive(false);
        const droppedFiles = 'dataTransfer' in event
            ? event.dataTransfer?.files
            : event.target?.files;
        if (!droppedFiles)
            return;
        // Filter out folders and fake files (folders with extensions)
        const validFiles = [];
        if ('dataTransfer' in event && event.dataTransfer) {
            const items = Array.from(event.dataTransfer.items);
            for (const item of items) {
                // Check if it's a directory using webkitGetAsEntry
                if (item.webkitGetAsEntry) {
                    const entry = item.webkitGetAsEntry();
                    if (entry && entry.isDirectory) {
                        toast.error('Folder upload is not supported.');
                        continue; // Skip folders
                    }
                }
                // Get file if it's valid
                if (item.kind === 'file') {
                    const file = item.getAsFile();
                    if (file) {
                        validFiles.push(file);
                    }
                }
            }
        }
        else {
            // For input file selection (safer, browsers don't allow folder selection here)
            validFiles.push(...Array.from(droppedFiles));
        }
        const droppedOrSelectedFiles = validFiles;
        if (maxFiles && droppedOrSelectedFiles.length > maxFiles) {
            if (onMaxFilesError)
                onMaxFilesError();
            return;
        }
        const accepted = [];
        const rejected = [];
        for (const file of droppedOrSelectedFiles) {
            if (maxFiles && files.accepted.length + accepted.length >= maxFiles) {
                if (onMaxFilesError)
                    onMaxFilesError();
                break;
            }
            const errors = validateFile(file);
            if (!checkEmpty(errors)) {
                rejected.push({ file, errors });
            }
            else {
                accepted.push(file);
            }
        }
        if (!checkEmpty(rejected)) {
            handleRejectedFiles(rejected);
        }
        // Rest of your existing setFiles logic remains the same...
        setFiles((prevFiles) => ({
            accepted: [
                ...prevFiles.accepted,
                ...accepted.filter((newFile) => !prevFiles.accepted.some((file) => file.name === newFile.name &&
                    getExtensionWithPeriod(file) ===
                        getExtensionWithPeriod(newFile) &&
                    file.lastModified === newFile.lastModified)),
            ],
            rejected: [],
        }));
        if ('dataTransfer' in event) {
            event.dataTransfer?.clearData();
        }
        else {
            event.target.value = '';
        }
        if (onDrop)
            onDrop(accepted, rejected, event);
    }, [maxFiles, validateFile, onMaxFilesError, onDrop, files.accepted]);
    const handleDragOver = useCallback((event) => {
        if (disabledDragAndDrop) {
            event.preventDefault();
            return;
        }
        event.preventDefault();
        setIsDragActive(true);
    }, []);
    const handleDragLeave = useCallback((event) => {
        if (disabledDragAndDrop) {
            event.preventDefault();
            return;
        }
        setIsDragActive(false);
    }, []);
    const getRootProps = useCallback(() => ({
        onDragOver: handleDragOver,
        onDragLeave: handleDragLeave,
        onDrop: handleDrop,
    }), [handleDragOver, handleDragLeave, handleDrop]);
    const getInputProps = useCallback(() => ({
        type: 'file',
        onChange: handleDrop,
        multiple,
        accept: accept ? accept.join(',') : '',
    }), [handleDrop, multiple, accept]);
    return {
        getRootProps,
        getInputProps,
        acceptedFiles: files.accepted,
        rejectedFiles: files.rejected,
        isDragActive,
        handleRemoveClick,
        handleReplaceClick,
    };
};
export default useFileDropzone;
//# sourceMappingURL=useFileDropzone.js.map