import { FileUploadState, FileUploadError, FileUploadEvent, FileUploadErrorReason } from "../types";
import { ErrorType } from "../types";
export const setUpDragHandler = (nileFileUpload, dragHandler) => {
    dragHandler.setIsDisabled(() => {
        return nileFileUpload.state === FileUploadState.DISABLED;
    });
    dragHandler.onStateChange((newState) => {
        nileFileUpload.state = newState;
    });
    dragHandler.onFileDrop((files) => {
        if (nileFileUpload.state === FileUploadState.DISABLED)
            return;
        nileFileUpload.errorMessage = '';
        const maxSize = parseSize(nileFileUpload.size);
        const uploadedFiles = nileFileUpload.uploadedFiles;
        if (!nileFileUpload.allowMultiple && (uploadedFiles.length + files.length > 1)) {
            nileFileUpload.errorMessage = FileUploadError.MULTIPLE_NOT_ALLOWED;
            nileFileUpload.requestUpdate();
            return;
        }
        let sizeExceeded = false;
        let duplicatesFound = false;
        const newFiles = [];
        const rejectedFiles = [];
        for (const file of files) {
            if (file.size > maxSize) {
                sizeExceeded = true;
                rejectedFiles.push(file);
                continue;
            }
            if (!nileFileUpload.allowDuplicates &&
                uploadedFiles.some((uploaded) => uploaded.name === file.name &&
                    uploaded.size === file.size &&
                    uploaded.type === file.type)) {
                duplicatesFound = true;
                rejectedFiles.push(file);
                continue;
            }
            if (!rejectedFiles.includes(file)) {
                newFiles.push(file);
            }
        }
        if (sizeExceeded) {
            nileFileUpload.errorMessage = FileUploadError.SIZE_LIMIT_EXCEEDED;
            const sizeExceededFiles = rejectedFiles.filter(file => file.size > maxSize);
            nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_ERROR, {
                detail: {
                    files: sizeExceededFiles,
                    type: FileUploadErrorReason.SIZE_LIMIT_EXCEEDED,
                    errorType: ErrorType.VALIDATION,
                    message: FileUploadError.SIZE_LIMIT_EXCEEDED,
                },
                bubbles: true,
                composed: true,
            }));
            nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_SIZE_EXCEED_FILES, {
                detail: { files: rejectedFiles }
            }));
            nileFileUpload.requestUpdate();
        }
        if (duplicatesFound && newFiles.length === 0) {
            nileFileUpload.errorMessage = FileUploadError.DUPLICATES_NOT_ALLOWED;
            nileFileUpload.requestUpdate();
        }
        let updatedFiles = [];
        if (nileFileUpload.allowedTypes.length > 0) {
            for (const file of newFiles) {
                if (nileFileUpload.allowedTypes.includes(file.type)) {
                    updatedFiles.push(file);
                }
                else {
                    nileFileUpload.errorMessage = FileUploadError.INVALID_FORMAT;
                }
            }
        }
        if (updatedFiles.length === 0) {
            updatedFiles = newFiles;
        }
        nileFileUpload.uploadedFiles = [...uploadedFiles, ...updatedFiles];
        nileFileUpload.requestUpdate();
    });
    dragHandler.setErrorMessage((errorMessage) => {
        nileFileUpload.errorMessage = errorMessage;
    });
};
export const addGlobalListeners = (dragHandler) => {
    document.addEventListener('dragover', dragHandler.preventDragOver, { passive: false });
    document.addEventListener('drop', dragHandler.preventDrop, { passive: false });
};
export const addInternalListeners = (nileFileUpload, dragHandler, uploadRequests) => {
    nileFileUpload.addEventListener('mouseenter', (e) => handleHoverIn(nileFileUpload.setState, nileFileUpload.state));
    nileFileUpload.addEventListener('mouseleave', (e) => handleHoverOut(nileFileUpload.setState, nileFileUpload.state));
    nileFileUpload.addEventListener('dragenter', (e) => dragHandler.dragEnter(e));
    nileFileUpload.addEventListener('dragleave', (e) => dragHandler.dragLeave(e));
    nileFileUpload.addEventListener('dragover', (e) => dragHandler.dragOver(e));
    nileFileUpload.addEventListener('drop', (e) => dragHandler.drop(e));
    const clickHandler = nileFileUpload.browseFiles.bind(nileFileUpload);
    const observer = new ResizeObserver(entries => {
        for (const entry of entries) {
            if (entry.contentRect.width < 400) {
                nileFileUpload.horizontalDiv.addEventListener('click', clickHandler);
            }
            else {
                nileFileUpload.horizontalDiv.removeEventListener('click', clickHandler);
            }
        }
    });
    observer.observe(nileFileUpload.horizontalDiv);
    cancelFileUpload(nileFileUpload, uploadRequests);
    removeFile(nileFileUpload.uploadedFiles, nileFileUpload);
};
export function handleHoverIn(setState, currentState) {
    if (currentState === FileUploadState.DEFAULT) {
        setState(FileUploadState.HOVER);
    }
}
export function handleHoverOut(setState, currentState) {
    if (currentState === FileUploadState.HOVER) {
        setState(FileUploadState.DEFAULT);
    }
}
export function uploadFiles(nileFileUpload) {
    const { uploadedFiles, fileUploadUrl, uploadRequests } = nileFileUpload;
    if (!fileUploadUrl || !uploadedFiles?.length)
        return;
    for (const file of uploadedFiles) {
        if (uploadRequests.has(file))
            continue;
        if (nileFileUpload.doNotUpload.includes(file))
            continue;
        if (file.errorMessage)
            continue;
        const formData = new FormData();
        formData.append('file', file);
        const xhr = new XMLHttpRequest();
        uploadRequests.set(file, xhr);
        nileFileUpload.emit(FileUploadEvent.NILE_UPLOADING);
        xhr.upload.onprogress = (e) => {
            const percent = Math.floor((e.loaded / e.total) * 100);
            nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_UPLOAD_PROGRESS, {
                detail: { file, progress: percent },
                bubbles: true,
                composed: true,
            }));
        };
        xhr.onload = () => {
            if (xhr.status >= 200 && xhr.status < 300) {
                nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_UPLOAD_SUCCESS, {
                    detail: { file, response: xhr.response },
                    bubbles: true,
                    composed: true,
                }));
            }
            else {
                nileFileUpload.errorMessage = FileUploadError.SERVER_SIDE_ERROR;
                nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.SERVER_SIDE_ERROR, {
                    detail: { file, status: xhr.status, response: xhr.response }
                }));
                nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_ERROR, {
                    detail: {
                        type: FileUploadErrorReason.SERVER_SIDE_ERROR,
                        file,
                        status: xhr?.status || 0,
                        response: xhr?.response,
                        message: FileUploadError.SERVER_SIDE_ERROR,
                        errorType: ErrorType.SERVER,
                    },
                    bubbles: true,
                    composed: true,
                }));
                nileFileUpload.requestUpdate();
            }
        };
        xhr.onerror = () => {
            uploadRequests.delete(file);
            nileFileUpload.doNotUpload.push(file);
            nileFileUpload.errorMessage = FileUploadError.NETWORK_ERROR;
            nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_ERROR, {
                detail: {
                    type: FileUploadErrorReason.NETWORK_ERROR,
                    file,
                    status: xhr.status,
                    response: xhr.response,
                    errorType: ErrorType.NETWORK,
                    message: FileUploadError.NETWORK_ERROR,
                },
                bubbles: true,
                composed: true,
            }));
            nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_NETWORK_ERROR, {
                detail: { file, status: xhr.status, response: xhr.response },
                bubbles: true,
                composed: true,
            }));
        };
        xhr.open('POST', fileUploadUrl);
        xhr.send(formData);
    }
}
export const cancelFileUpload = (nileFileUpload, uploadRequests) => {
    document.addEventListener(FileUploadEvent.NILE_CANCEL_UPLOAD, (e) => {
        const fileToCancel = e.detail.file;
        const xhr = uploadRequests.get(fileToCancel);
        if (xhr) {
            xhr.abort();
        }
        uploadRequests.delete(fileToCancel);
        nileFileUpload.uploadedFiles = nileFileUpload.uploadedFiles.filter(file => file !== fileToCancel);
        nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_ERROR, {
            detail: {
                type: FileUploadErrorReason.UPLOAD_CANCELLED,
                file: fileToCancel,
                message: FileUploadError.UPLOAD_CANCELLED,
                errorType: ErrorType.UPLOAD_CANCELLED,
            },
            bubbles: true,
            composed: true,
        }));
        nileFileUpload.dispatchEvent(new CustomEvent(FileUploadEvent.NILE_UPLOAD_CANCELLED, {
            detail: { file: fileToCancel }
        }));
    });
};
function parseSize(sizeStr) {
    const units = { B: 1, KB: 1024, MB: 1024 ** 2, GB: 1024 ** 3 };
    const num = parseFloat(sizeStr);
    const unit = sizeStr.replace(/[0-9.\s]/g, '').toUpperCase();
    const multiplier = units[unit] || 1;
    return num * multiplier;
}
export const preventDefaultAndStopPropagation = (event) => {
    event.preventDefault?.();
    event.stopPropagation();
};
export const removeFile = (uploadedFiles, nileFileUpload) => {
    document.addEventListener('nile-remove', (e) => {
        const { value } = e.detail;
        uploadedFiles = uploadedFiles.filter(file => file !== value);
        nileFileUpload.uploadedFiles = uploadedFiles;
        nileFileUpload.errorMessage = '';
        nileFileUpload.requestUpdate();
    });
};
export const truncateString = (nileFileUpload) => {
    if (nileFileUpload.variant === 'vertical' && nileFileUpload.errorMessage.length > 34) {
        nileFileUpload.isStringTruncated = true;
        nileFileUpload.requestUpdate();
    }
    else if (nileFileUpload.variant === 'horizontal' && nileFileUpload.errorMessage.length > 96) {
        nileFileUpload.isStringTruncated = true;
        nileFileUpload.requestUpdate();
    }
};
//# sourceMappingURL=file-validation.util.js.map