"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useFileUploader = void 0;
const declensionOfWords_1 = require("@astral/utils/declension/declensionOfWords");
const formatFileSizeToView_1 = require("@astral/utils/file/formatFileSizeToView");
const react_1 = require("react");
const useGenerateLocalId_1 = require("../../../useGenerateLocalId");
const useId_1 = require("../../../useId");
const constants_1 = require("../../constants");
const restrictions_1 = require("../../restrictions");
const compareFile_1 = require("../../utils/compareFile");
const rulePipe_1 = require("../../utils/rulePipe");
const toArray_1 = require("../../utils/toArray");
const useDnD_1 = require("../useDnD");
const useUploadFiles_1 = require("../useUploadFiles");
const hooks_1 = require("./hooks");
const useFileUploader = ({ value, isDisabled, isMultiple, accept, restrictions = [], maxFileSize, maxFileCount = 1, // для случая, когда isMultiple=false
inputRef, notify, onChange, onUploadFile, onDeleteFile, name, isError, onView, generateDownloadLink, placeholder, helperText, label, className, getErrorMessage, }) => {
    const inputId = (0, useId_1.useId)();
    const [deletingFileId, setDeletingFileId] = (0, react_1.useState)(null);
    const { generateId } = (0, useGenerateLocalId_1.useGenerateLocalId)();
    const acceptMeta = (0, hooks_1.usePrepareAccept)(accept);
    // Преобразуем value к массиву
    const files = (0, react_1.useMemo)(() => (0, toArray_1.toArray)(value), [value]);
    // true, если достигли лимита по кол-ву файлов при isMultiple=true
    const isLimitMaxFileCount = isMultiple ? files.length >= maxFileCount : false;
    const isVisibleAddFile = isMultiple ? !isLimitMaxFileCount : !files.length;
    const isVisibleFileList = Boolean(files.length);
    const restrict = (file) => {
        return (0, rulePipe_1.rulePipe)((0, restrictions_1.restrictFileMaxSize)(formatFileSizeToView_1.formatFileSizeToView, maxFileSize), (0, restrictions_1.restrictFileType)(acceptMeta), ...restrictions)(file);
    };
    const declensionFile = (0, declensionOfWords_1.declensionOfWords)(['файл', 'файла', 'файлов']);
    const declensionAdded = (0, declensionOfWords_1.declensionOfWords)([
        'Добавлен',
        'Добавлено',
        'Добавлено',
    ]);
    const notifyWarning = (addedFilesLength, droppedFilesLength) => {
        const title = droppedFilesLength === 1
            ? 'Файл не загружен'
            : `${declensionAdded(addedFilesLength)} ${addedFilesLength} ${declensionFile(addedFilesLength)} из ${droppedFilesLength}`;
        notify?.warning(title, {
            content: 'Вы превысили максимально допустимое количество файлов для загрузки',
        });
    };
    const getInitialStatusUploadFile = (error) => {
        if (error) {
            return {
                ...constants_1.DEFAULT_FILE_STATUS,
                isRestrictionError: Boolean(error),
                errorMsg: error.message,
            };
        }
        return constants_1.DEFAULT_FILE_STATUS;
    };
    const { enqueueFiles, refetchFile, selfFiles, setErrorStatusFile } = (0, useUploadFiles_1.useUploadFiles)({
        files,
        isMultiple,
        onChange,
        onUploadFile,
        getErrorMessage,
    });
    const handleChange = (event) => {
        // Преобразуем к массиву и удаляем дубликаты
        const droppedFiles = Array.from(event.target.files || []).filter((droppedFile) => !files.find((file) => (0, compareFile_1.compareFile)(droppedFile, file)));
        const addedFiles = droppedFiles
            .slice(0, maxFileCount - files.length)
            .reduce((acc, droppedFile) => {
            const error = restrict(droppedFile);
            return [
                // biome-ignore lint/performance/noAccumulatingSpread: <>
                ...acc,
                {
                    id: `${inputId}${generateId()}`,
                    name: droppedFile.name,
                    type: droppedFile.type,
                    size: droppedFile.size,
                    file: droppedFile,
                    status: getInitialStatusUploadFile(error),
                },
            ];
        }, []);
        if (isMultiple) {
            onChange([...files, ...addedFiles]);
        }
        else if (addedFiles.length) {
            onChange(addedFiles[0]);
        }
        if (addedFiles.length < droppedFiles.length) {
            notifyWarning(addedFiles.length, droppedFiles.length);
        }
        enqueueFiles(addedFiles);
    };
    const { isDragActive, ...dropZoneActions } = (0, useDnD_1.useDnD)({
        isDisabled,
        onChange: (droppedFiles) => {
            handleChange({
                target: { files: droppedFiles },
            });
        },
    });
    const handleDelete = (fileId) => {
        const deleteFile = () => {
            if (isMultiple) {
                return onChange(files?.filter(({ id }) => id !== fileId));
            }
            return onChange(null);
        };
        if (!onDeleteFile) {
            return deleteFile();
        }
        setDeletingFileId(fileId);
        onDeleteFile(fileId)
            .then(deleteFile)
            .catch(() => notify.error('Ошибка удаления файла'))
            .finally(() => setDeletingFileId(null));
    };
    const getHandlerOnRetry = () => {
        if (onUploadFile) {
            return (fileId, file) => refetchFile({ id: fileId, file });
        }
        return undefined;
    };
    return {
        dropZoneProps: {
            isActive: !isDisabled && isDragActive,
            htmlFor: inputId,
            isDisabled,
            isError,
            className: constants_1.fileUploaderClassnames.dropzone,
            ...dropZoneActions,
            isLimitMaxFileCount,
            maxFileCount: maxFileCount,
            isVisibleAddFile,
            isVisibleFileList,
            hintPlaceholderProps: {
                isMultiple,
                accept,
                maxFileCount: maxFileCount,
                maxFileSize,
                placeholder,
            },
            fileInputProps: {
                id: inputId,
                accept: accept.join(),
                ref: inputRef,
                value: '',
                onChange: handleChange,
                name,
                isMultiple,
                isDisabled,
            },
            uploadButtonProps: {
                isDisabled,
                htmlFor: inputId,
            },
            containerProps: {
                className,
                label,
                isError,
                helperText,
            },
        },
        fileListProps: {
            onDelete: handleDelete,
            onRetry: getHandlerOnRetry(),
            onView,
            generateDownloadLink,
            isMultiple,
            files,
            selfFiles,
            setErrorStatusFile,
            getErrorMessage,
            deletingFileId,
        },
    };
};
exports.useFileUploader = useFileUploader;
