// import JSZip from 'jszip';
// import $, {ajax} from "jquery";
// import Dropzone from 'dropzone';
//
// interface DropzoneFileWithServerId extends Dropzone.DropzoneFile {
//     serverId?: string;
// }
//
// $(function () {
//
//
//     $(".dz-button").removeClass("dz-button").addClass("btn btn-light dz-cust");
//     $('#submitbutton').prop("disabled", true);
//
//     if (window.location.href.indexOf("/de/") > -1) {
//         $(".dz-cust").html("<i class=\"icofont-plus-circle f-22\"></i> <span style='font-size: 26px'> Dateien hochladen</span>");
//     }
//
//     if (window.location.href.indexOf("/en/") > -1) {
//         $(".dz-cust").html("<i class=\"icofont-plus-circle f-22\"></i> <span style='font-size: 22px'> Upload Files</span>");
//     }
//
//     if (window.location.href.indexOf("/es/") > -1) {
//         $(".dz-cust").html("<i class=\"icofont-plus-circle f-22\"></i> <span style='font-size: 26px'> Cargar archivos</span>");
//     }
//
//     if (window.location.href.indexOf("/ru/") > -1) {
//         $(".dz-cust").html("<i class=\"icofont-plus-circle f-22\"></i> <span style='font-size: 26px'> Загрузка файлов</span>");
//     }
//
//     $('#shared_file_contact').on('change', function() {
//         checkFormState();
//     });
//
//     $('#chooseUserFree').on('input', function() {
//         checkFormState();
//     });
//
//     $('#shared_file_title, #shared_file_message').on('input', function () {
//         checkFormState();
//     });
//
//     $('#shared_file_contactEmail').on('input', function () {
//         checkFormState();
//     });
// })
//
// const license: string = $('#aLXq676F8V6arDsukGLrsnKkdvc7Jv5TKu9F6aSWaVaVaujkmF').val() as string
//
// //o9zZ
// //mdzPzA==
// let maxFilesizeVal = 200000;
// let maxFilesizeValShow = Number(maxFilesizeVal / 1000) + ' GB'
// if (license == 'o9zZ') {
//     maxFilesizeVal = 200000
//     maxFilesizeValShow = Number(maxFilesizeVal / 1000) + ' GB'
// }
// $('#maxUploadSize').text(maxFilesizeValShow)
// //alert(maxFilesizeVal)
// Dropzone.options.docUpload = {
//     maxFilesize: maxFilesizeVal,
//     addRemoveLinks: true,
//     dictCancelUpload: '<i class="icofont-stop icofont-2x" style="position: absolute; cursor: pointer; margin-top: -20px; margin-left: -15px; z-index: 10000"></i>',
//     dictRemoveFile: "<i class=\"d-none d-md-block icofont-delete-alt icofont-2x text-danger\" style=\"position: absolute; cursor: pointer; margin-top: -28px; margin-left: 45px;z-index: 10000\"></i><svg class='d-block d-md-none' style='position: absolute; margin-left: -26px; cursor: pointer; z-index: 10000;' width=\"20\" height=\"20\" viewBox=\"0 0 50 50\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g clip-path=\"url(#clip0_348_833)\"><line x1=\"0.707107\" y1=\"-0.707107\" x2=\"50.7071\" y2=\"49.2929\" stroke=\"currentColor\" stroke-width=\"2\"/><line x1=\"50.7071\" y1=\"0.707107\" x2=\"0.707108\" y2=\"50.7071\" stroke=\"currentColor\" stroke-width=\"2\"/></g><defs><clipPath id=\"clip0_348_833\"><rect width=\"50\" height=\"50\" fill=\"currentColor\"/></clipPath></defs></svg>",
//     init: function () {
//         this.on("success", function (file: DropzoneFileWithServerId, response: any) {
//             file.serverId = response.id;
//             $('.dz-default').show()
//             $('.dz-cust').show()
//             //$('#uploader').hide();
//             //$('#uploadData').show();
//             //$('#submitbutton').prop("disabled",false);
//             $(file.previewElement).find('.dz-success-mark').remove();
//             $('#the-progress-div').hide();
//             updateFileVisibility();
//             checkFormState();
//         });
//         this.on("sending", function (file, xhr, formData) {
//             $('#the-progress-div').show();
//             $('#submitbutton').prop("disabled", true);
//             //$('#uploader').show();
//             //$('#uploadData').hide();
//         });
//         this.on("totaluploadprogress", function (progress) {
//             $("#the-progress-div").width(progress.toFixed(0) + '%');
//             $(".the-progress-text").text(progress.toFixed(0) + '%');
//             //$('#submitbutton').prop("disabled",false);
//         });
//         this.on("removedfile", function (file: DropzoneFileWithServerId) {
//             const locale = window.location.pathname.split('/')[2];
//             const url = `/app/${locale}/upload/${file.serverId}/remove`;
//             console.log('newee');
//             ajax({
//                 method: 'POST',
//                 url: url,
//                 success: function (response: any) {
//                     if (response.success === true) {
//                         updateFileVisibility();
//                         checkFormState();
//                     }
//                 },
//             });
//         });
//     }
// };
//
//
// const fileContainer = $('#docUpload');  // Указание на форму с id "docUpload"
// const toggleButton = $('<button id="toggleFiles" class="toggle-files" type="button" style="display: none;">Show more</button>');
// fileContainer.after(toggleButton);
//
// function updateFileVisibility() {
//     const filePreviews = fileContainer.find('.dz-preview');
//
//     if (!fileContainer.hasClass('show-all')) {
//         filePreviews.each(function (index) {
//             if (index >= 3) {
//                 $(this).addClass('d-none');
//             } else {
//                 $(this).removeClass('d-none');
//             }
//         });
//     }
//
//     if (filePreviews.length > 3) {
//         toggleButton.show();
//         if (!fileContainer.hasClass('show-all')) {
//             toggleButton.text('Show more');
//         }
//     } else {
//         toggleButton.hide();
//     }
// }
//
// toggleButton.on('click', function () {
//     if (fileContainer.hasClass('show-all')) {
//         fileContainer.removeClass('show-all');
//         fileContainer.find('.dz-preview').each(function (index) {
//             if (index >= 3) {
//                 $(this).addClass('d-none');
//             }
//         });
//         toggleButton.text('Show more');
//     } else {
//         fileContainer.addClass('show-all');
//         fileContainer.find('.dz-preview').removeClass('d-none');
//         toggleButton.text('Hide');
//     }
// });
//
// const folderInput = document.getElementById('folderInput') as HTMLInputElement;
// const uploadFolderButton = document.getElementById('uploadFolderBtn') as HTMLButtonElement;
//
// // Обработчик для выбора папок
// uploadFolderButton.addEventListener('click', () => {
//     folderInput.click();
// });
//
// // Слушаем выбор файлов/папок
// folderInput.addEventListener('change', async (event: Event) => {
//     const input = event.target as HTMLInputElement;
//     if (input.files && input.files.length > 0) {
//         const files = Array.from(input.files);
//         const zip = new JSZip();
//
//         // Организация файлов в ZIP
//         const firstFile = files[0];
//         const folderName = firstFile.webkitRelativePath.split('/')[0];
//
//
//         files.forEach((file) => {
//             zip.file(file.webkitRelativePath, file);
//         });
//
//         // Генерация ZIP-архива
//         const zipBlob = await zip.generateAsync({ type: 'blob' });
//         const zipFileName = folderName ? `${folderName}.zip` : 'archive.zip';
//         const zipFile = new File([zipBlob], zipFileName, { type: 'application/zip' });
//
//         // Добавление ZIP в Dropzone
//         const dropzoneInstance = Dropzone.forElement('#docUpload');
//         dropzoneInstance.addFile(zipFile as any);    }
// });
//
// function checkFormState() {
//     const userSelected = $('#shared_file_contact').val() || $('#chooseUserFree').val();
//     const filesUploaded = fileContainer.find('.dz-preview').length > 0;
//     const emailSelected = String($('#shared_file_contactEmail').val()).trim() !== '';
//
//
//     // Приведение значений к строке и использование метода trim
//     const titleFilled = String($('#shared_file_title').val()).trim() !== '';
//     const messageFilled = String($('#shared_file_message').val()).trim() !== '';
//
//
//     if (filesUploaded && titleFilled && messageFilled) {
//         if(userSelected || emailSelected ) {
//             $('#submitbutton').prop("disabled", false);
//             return true;
//         }
//     } else {
//         $('#submitbutton').prop("disabled", true);
//         return false;
//     }
// }

import $, {ajax} from "jquery";
import Dropzone from 'dropzone';

interface DropzoneFileWithServerId extends Dropzone.DropzoneFile {
    serverId?: string;
}

function isIgnoredSystemFile(fileName?: string | null): boolean {
    const ignoredNames = new Set([
        '.ds_store',
        'desktop.ini',
        'thumbs.db',
        'ehthumbs.db',
        'ehthumbs_vista.db',
    ]);

    return ignoredNames.has((fileName ?? '').trim().toLowerCase());
}

function getUploadFileSizeBytes(file: DropzoneFileWithServerId): number {
    return file.size || 0;
}

function isUsableUploadFilename(name?: string | null): boolean {
    const trimmed = (name ?? '').trim();
    if (trimmed === '' || trimmed === '.') {
        return false;
    }

    const base = trimmed.split(/[/\\]/).pop()?.toLowerCase() ?? '';
    return base !== 'blob' && base !== 'blob.bin';
}

function getOriginalUploadFilename(file: DropzoneFileWithServerId): string {
    const relativeName = file.webkitRelativePath?.split(/[/\\]/).pop();
    const candidates = [
        file.name,
        relativeName,
    ];

    for (const candidate of candidates) {
        if (isUsableUploadFilename(candidate)) {
            return String(candidate).split(/[/\\]/).pop() as string;
        }
    }

    return file.name || 'upload.bin';
}

/** Split name into base + extension so CSS can ellipsize the base only (Testdokum….pdf). */
function applyTruncatableFilename(preview: Element, filename: string): void {
    const nameEl = preview.querySelector('[data-dz-name]') as HTMLElement | null;
    if (!nameEl) {
        return;
    }

    const lastDot = filename.lastIndexOf('.');
    const hasExt = lastDot > 0 && lastDot < filename.length - 1;
    const base = hasExt ? filename.slice(0, lastDot) : filename;
    const ext = hasExt ? filename.slice(lastDot) : '';

    nameEl.replaceChildren();
    nameEl.classList.add('dz-filename-display');
    nameEl.title = filename;

    const baseSpan = document.createElement('span');
    baseSpan.className = 'dz-filename-base';
    baseSpan.textContent = base;
    nameEl.appendChild(baseSpan);

    if (ext) {
        const extSpan = document.createElement('span');
        extSpan.className = 'dz-filename-ext';
        extSpan.textContent = ext;
        nameEl.appendChild(extSpan);
    }
}

/** Keep delete as last child of the preview row so it can align right. */
function placeRemoveAtRowEnd(preview: Element): void {
    const remove = preview.querySelector('a.dz-remove') as HTMLElement | null;
    if (!remove) {
        return;
    }
    preview.appendChild(remove);
    remove.style.position = 'static';
    remove.style.left = 'auto';
    remove.style.top = 'auto';
    remove.style.transform = 'none';
    remove.style.margin = '0';
    remove.querySelectorAll('i, svg').forEach((node) => {
        const el = node as HTMLElement;
        el.style.position = 'static';
        el.style.margin = '0';
        el.style.left = 'auto';
        el.style.top = 'auto';
    });
}

function decorateFilePreview(file: DropzoneFileWithServerId): void {
    const preview = file.previewElement;
    if (!preview) {
        return;
    }
    applyTruncatableFilename(preview, file.name || '');
    placeRemoveAtRowEnd(preview);

    // Dropzone leaves empty siblings in the preview that break one-line flex/grid layouts.
    preview.querySelectorAll('.dz-image, .dz-progress, .dz-error-message, .dz-success-mark, .dz-error-mark').forEach((el) => {
        (el as HTMLElement).style.display = 'none';
    });
}

const PROGRESS_CIRCUMFERENCE = 2 * Math.PI * 40;
/** Never let the UI jump backwards between chunks (sending fires per chunk). */
let lastDisplayedProgress = 0;
let successFlashShown = false;
/** True while folder files are still being addFile()'d – avoid premature success flash. */
let folderQueueInProgress = false;

function setUploadProgress(progress: number, statusText?: string, spinning = false): void {
    const circle = $('#upload-progress-circle');
    const ring = $('#upload-progress-ring');
    const value = $('#upload-progress-value');
    const percent = $('#upload-progress-percent');
    const status = $('#upload-progress-status');
    let clamped = Math.max(0, Math.min(100, progress));

    // Keep progress monotonic while an upload session is visible.
    if (!spinning && circle.hasClass('is-active')) {
        clamped = Math.max(lastDisplayedProgress, clamped);
    }
    lastDisplayedProgress = clamped;

    circle.addClass('is-active').show();
    percent.text(Math.round(clamped) + '%');

    if (statusText) {
        status.text(statusText);
    } else if (clamped >= 99.5) {
        status.text(getUploadFinishingMessage());
    }

    if (spinning && clamped <= 0) {
        ring.removeClass('is-determinate');
    } else {
        ring.addClass('is-determinate');
        value.css('stroke-dashoffset', String(PROGRESS_CIRCUMFERENCE * (1 - clamped / 100)));
    }
}

function hideUploadProgress(): void {
    lastDisplayedProgress = 0;
    $('#upload-progress-circle').removeClass('is-active').hide();
    $('#upload-progress-percent').text('0%');
    $('#upload-progress-value').css('stroke-dashoffset', String(PROGRESS_CIRCUMFERENCE));
    $('#upload-progress-ring').removeClass('is-determinate');
}

/**
 * Overall progress across active files.
 * For chunked uploads Dropzone's totaluploadprogress uses chunk totals as file.upload.total,
 * which makes the UI jump 0→100% per chunk. Prefer file.upload.progress (chunk average)
 * weighted by file.size.
 */
function getOverallUploadProgress(dz: Dropzone): number {
    const activeFiles = dz.getActiveFiles();
    if (!activeFiles.length) {
        return 100;
    }

    let totalBytes = 0;
    let sentBytes = 0;

    for (const file of activeFiles) {
        const size = typeof file.size === 'number' && file.size > 0
            ? file.size
            : (file.upload?.total || 0);
        if (size <= 0) {
            continue;
        }

        totalBytes += size;

        const upload: any = file.upload || {};
        if (upload.chunked && upload.totalChunkCount > 0) {
            // file.upload.progress is sum(chunk.progress) / totalChunkCount (0–100)
            const fileProgress = Math.max(0, Math.min(100, Number(upload.progress) || 0));
            sentBytes += size * (fileProgress / 100);
        } else {
            const bytesSent = Number(upload.bytesSent) || 0;
            sentBytes += Math.min(size, bytesSent);
        }
    }

    if (totalBytes <= 0) {
        return 0;
    }

    return Math.max(0, Math.min(100, (100 * sentBytes) / totalBytes));
}

function getUploadFinishedMessage(): string {
    const source = document.getElementById('folderInput');

    return source?.dataset.uploadFinishedMessage || 'Upload completed.';
}

function getUploadCanceledMessage(): string {
    const source = document.getElementById('upload-progress-circle');

    return source?.dataset.uploadCanceled || 'Upload canceled.';
}

function getUploadFinishingMessage(): string {
    const source = document.getElementById('upload-progress-circle');

    return source?.dataset.uploadFinishing || 'Finishing…';
}

function notifyUploadFinished(): void {
    if (successFlashShown || folderQueueInProgress) {
        return;
    }
    successFlashShown = true;
    hideUploadProgress();
    showSuccessFlash(getUploadFinishedMessage());
}

function beginUploadSession(): void {
    successFlashShown = false;
}

function isUploadCanceledMessage(message: unknown): boolean {
    if (typeof message !== 'string') {
        return false;
    }
    const canceled = getUploadCanceledMessage();

    return message === canceled
        || message === 'Upload canceled.'
        || /upload canceled\.?/i.test(message)
        || /upload abgebrochen\.?/i.test(message);
}

function showSuccessFlash(message: string): void {
    showFlashMessage('success', message);
}

function showErrorFlash(message: string): void {
    showFlashMessage('danger', message);
}

function showPrimaryFlash(message: string): void {
    showFlashMessage('primary', message);
}

function showFlashMessage(label: 'success' | 'danger' | 'primary' | 'info' | 'warning', message: string): void {
    const globalShowFlash = (window as any).showFlash;
    if (typeof globalShowFlash === 'function') {
        globalShowFlash(label, message);
        return;
    }

    const flashContainer = document.getElementById('flash-messages');
    if (!flashContainer) {
        console.error(message);
        return;
    }

    const icon = label === 'success' ? '✓'
        : (label === 'danger' ? '×'
            : (label === 'warning' ? '!'
                : (label === 'info' ? '?' : 'i')));

    const flashElement = document.createElement('div');
    flashElement.className = `flash-message flash-message--${label}`;
    flashElement.innerHTML = `
        <div class="flash-message__icon">${icon}</div>
        <div class="flash-message__text">
            <div class="headline">${(window as any).getFlashHeadline?.(label) ?? (window as any).flashHeadlines?.default ?? 'Hinweis'}</div>
            <div class="subtext">${message}</div>
        </div>
        <button class="flash-message__close" aria-label="${(window as any).flashHeadlines?.close ?? 'Close'}">&times;</button>
    `;

    flashContainer.appendChild(flashElement);
    const closeBtn = flashElement.querySelector('.flash-message__close');
    closeBtn?.addEventListener('click', () => flashElement.remove());
    setTimeout(() => flashElement.remove(), 5000);
}

function suppressBrowserAlerts(): void {
    const win = window as any;
    if (win.__uploadAlertSuppressed) {
        return;
    }
    win.__uploadAlertSuppressed = true;
    win.alert = (message?: unknown) => {
        const text = String(message ?? '');
        if (isUploadCanceledMessage(text)) {
            showPrimaryFlash(getUploadCanceledMessage());
            return;
        }
        showErrorFlash(text);
    };
}

/** Dropzone uses window.confirm() for cancel – replace with direct cancel + primary flash. */
function disableNativeCancelConfirm(): void {
    Dropzone.confirm = function (_question: string, accepted: () => void, _rejected?: () => void) {
        return accepted();
    };
}

$(function () {
    suppressBrowserAlerts();
    disableNativeCancelConfirm();
    $(".dz-message").hide();
    $('#submitbutton').prop("disabled", true);

    $('#uploadFilesBtn').on('click', function () {
        const dropzoneInstance = Dropzone.forElement('#docUpload');
        // @ts-ignore
        dropzoneInstance.hiddenFileInput?.click();
    });

    $('#shared_file_email, #shared_file_contact, #shared_file_contactEmail').on('change input', function () {
        checkFormState();
    });

    $('#shared_file_title, #shared_file_message').on('input', function () {
        checkFormState();
    });
})

const license: string = $('#aLXq676F8V6arDsukGLrsnKkdvc7Jv5TKu9F6aSWaVaVaujkmF').val() as string

let maxFilesizeVal: number = parseInt($('#maxFilesizeMb').val() as string, 10);
let maxFilesizeValShow = Number(maxFilesizeVal / 1000) + ' GB'
$('#maxUploadSize').text(maxFilesizeValShow)

// @ts-ignore
Dropzone.options.docUpload = {
    // Chunking configuration
    chunking: true,
    forceChunking: true,
    chunkSize: 52428800, // 50 MB
    parallelChunkUploads: false,
    retryChunks: true,
    retryChunksLimit: 3,

    // Other settings
    maxFilesize: maxFilesizeVal,
    addRemoveLinks: true,
    timeout: 300000, // 5 minutes timeout for each chunk

    // Параметры для правильной передачи имени файла
    paramName: "file",
    // @ts-ignore
    renameFile: function (file) {
        return file.name;
    },

    dictCancelUpload: '<i class="icofont-stop icofont-2x" style="position: absolute; cursor: pointer; margin-top: 0; margin-left: -15px; z-index: 10000"></i>',
    dictRemoveFile: '<i class="d-none d-md-block icofont-delete-alt text-danger dz-remove-icon"></i><svg class="d-block d-md-none dz-remove-icon" width="16" height="16" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
    dictUploadCanceled: typeof document !== 'undefined'
        ? (document.getElementById('upload-progress-circle')?.dataset.uploadCanceled || 'Upload canceled.')
        : 'Upload canceled.',
    dictCancelUploadConfirmation: typeof document !== 'undefined'
        ? (document.getElementById('upload-progress-circle')?.dataset.uploadCanceled || 'Upload canceled.')
        : 'Upload canceled.',

    init: function () {
        this.on("addedfile", function (file: DropzoneFileWithServerId) {
            if (isIgnoredSystemFile(file?.name)) {
                // @ts-ignore
                this.removeFile(file);
                return;
            }
            decorateFilePreview(file);
            updateFileVisibility();
        });
        this.on("success", function (this: Dropzone, file: DropzoneFileWithServerId, response: any) {
            console.log('Upload success response:', response);

            if (response.success) {
                if (response.id != null) {
                    file.serverId = response.id;
                }
                $('.dz-default').show();
                $('.dz-cust').show();
                $(file.previewElement).find('.dz-success-mark').remove();
                if (file.previewElement) {
                    decorateFilePreview(file);
                }
                updateFileVisibility();
                checkFormState();

                // Show success as soon as the last file is done (don't wait for queuecomplete).
                if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
                    notifyUploadFinished();
                }

                if (response.completed) {
                    console.log('File upload completed:', response.file);
                }
            } else {
                console.error('Upload failed:', response.error);
                // @ts-ignore
                this.removeFile(file);
                showErrorFlash('Upload failed: ' + response.error);
            }
        });

        this.on("error", function (this: Dropzone, file: DropzoneFileWithServerId, errorMessage: any) {
            console.error('Upload error:', errorMessage);

            let message = 'Upload failed';
            if (typeof errorMessage === 'string') {
                message = errorMessage;
            } else if (errorMessage?.error === 'quota_exceeded') {
                message = errorMessage.message ?? 'Storage quota exceeded.';
            } else if (errorMessage?.error) {
                message = errorMessage.error;
            }

            // Dropzone emits error("Upload canceled.") on cancel – show primary flash, not danger/alert.
            // Do not call removeFile here: cancel already runs inside removeFile().
            if (isUploadCanceledMessage(message) || file.status === 'canceled') {
                showPrimaryFlash(getUploadCanceledMessage());
                hideUploadProgress();
                updateFileVisibility();
                checkFormState();
                return;
            }

            showErrorFlash(message);
            // @ts-ignore
            this.removeFile(file);
        });

        this.on("sending", function (file: DropzoneFileWithServerId, xhr, formData) {
            console.log('Sending file:', file.name);
            console.log('File size:', file.size);
            console.log('File type:', file.type);

            formData.append('dzoriginalfilename', getOriginalUploadFilename(file));
            formData.append('file_size', String(getUploadFileSizeBytes(file)));

            // Проверим, что передается в formData
            console.log('FormData entries:');
            // @ts-ignore
            for (let pair of formData.entries()) {
                console.log(pair[0] + ': ' + pair[1]);
            }

            // `sending` fires for every chunk – never reset progress to 0 mid-upload.
            if (!$('#upload-progress-circle').hasClass('is-active')) {
                beginUploadSession();
                setUploadProgress(0, undefined, true);
            } else {
                setUploadProgress(lastDisplayedProgress);
            }
            $('#submitbutton').prop("disabled", true);
        });

        this.on("uploadprogress", function (this: Dropzone, _file, _progress, _bytesSent) {
            // With chunking, Dropzone's totaluploadprogress is wrong (per-chunk bytes).
            // file.upload.progress is already averaged across chunks (0–100 for the whole file).
            setUploadProgress(getOverallUploadProgress(this));
        });

        this.on("totaluploadprogress", function (this: Dropzone) {
            setUploadProgress(getOverallUploadProgress(this));
        });

        this.on("canceled", function (this: Dropzone) {
            if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
                hideUploadProgress();
                updateFileVisibility();
                checkFormState();
            }
        });

        this.on("removedfile", function (this: Dropzone, file: DropzoneFileWithServerId) {
            if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
                hideUploadProgress();
                updateFileVisibility();
                checkFormState();
            }

            if (file.serverId) {
                const form = document.getElementById('docUpload');
                const template = form?.dataset.removeUrl || '';
                const url = template
                    ? template.replace('__FILE_ID__', String(file.serverId))
                    : `/app/${window.location.pathname.split('/')[2]}/upload/${file.serverId}/remove`;
                console.log('Removing file:', file.serverId);

                ajax({
                    method: 'POST',
                    url: url,
                    success: function (response: any) {
                        if (response.success === true) {
                            updateFileVisibility();
                            checkFormState();
                        }
                    },
                    error: function (xhr, status, error) {
                        console.error('Error removing file:', error);
                    }
                });
            }
        });

        // Обработка chunked upload
        this.on("chunksUploaded", function (file: DropzoneFileWithServerId, done: Function) {
            console.log('All chunks uploaded for file:', file.name);
            // Dropzone автоматически вызовет done() когда получит успешный ответ
            done();
        });
        this.on("queuecomplete", function (this: Dropzone) {
            if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
                if (this.getAcceptedFiles().length > 0) {
                    notifyUploadFinished();
                } else {
                    hideUploadProgress();
                }
            }
        });
    }
};

const fileContainer = $('#docUpload');
const filesFooter = $('#upload-files-footer');
const filesCountEl = $('#upload-files-count');
const toggleButton = $('#toggleFiles');

const PREVIEW_COLLAPSE_CLASS = 'dz-preview--truncated';
const MAX_VISIBLE_PREVIEWS = 3;

function getShowMoreLabel(): string {
    return fileContainer.attr('data-show-more') || 'Show more';
}

function getHideLabel(): string {
    return fileContainer.attr('data-hide') || 'Hide';
}

function formatUploadedFilesCount(count: number): string {
    const template = count === 1
        ? (fileContainer.attr('data-uploaded-file-count') || '%count% file')
        : (fileContainer.attr('data-uploaded-files-count') || '%count% files');

    return template.replace(/__COUNT__|%count%/g, String(count));
}

function updateFileVisibility() {
    const filePreviews = fileContainer.find('.dz-preview');
    const showAll = fileContainer.hasClass('show-all');
    const count = filePreviews.length;

    filePreviews.each(function (index) {
        const preview = $(this);
        if (!showAll && index >= MAX_VISIBLE_PREVIEWS) {
            preview.addClass(`${PREVIEW_COLLAPSE_CLASS} d-none`);
        } else {
            preview.removeClass(`${PREVIEW_COLLAPSE_CLASS} d-none`);
        }
    });

    if (count > 0) {
        filesFooter.prop('hidden', false);
        filesCountEl.text(formatUploadedFilesCount(count));
    } else {
        filesFooter.prop('hidden', true);
        filesCountEl.text('');
        fileContainer.removeClass('show-all');
    }

    if (count > MAX_VISIBLE_PREVIEWS) {
        toggleButton.prop('hidden', false);
        toggleButton.text(showAll ? getHideLabel() : getShowMoreLabel());
    } else {
        fileContainer.removeClass('show-all');
        toggleButton.prop('hidden', true);
        toggleButton.text(getShowMoreLabel());
    }
}

toggleButton.on('click', function () {
    if (fileContainer.hasClass('show-all')) {
        fileContainer.removeClass('show-all');
    } else {
        fileContainer.addClass('show-all');
    }
    updateFileVisibility();
});

const folderInput = document.getElementById('folderInput') as HTMLInputElement | null;
const uploadFolderButton = document.getElementById('uploadFolderBtn') as HTMLButtonElement | null;

uploadFolderButton?.addEventListener('click', () => {
    folderInput?.click();
});

folderInput?.addEventListener('change', async (event: Event) => {
    const input = event.target as HTMLInputElement;
    if (input.files && input.files.length > 0) {
        const files = Array.from(input.files);
        const firstFile = files[0];
        const folderName = firstFile.webkitRelativePath.split('/')[0];

        console.log(`Queueing ${files.length} files for folder: ${folderName}`);

        try {
            beginUploadSession();
            folderQueueInProgress = true;
            setUploadProgress(0, 'Queueing files...', true);

            const dropzoneInstance = Dropzone.forElement('#docUpload');
            const batchSize = 100;
            let queuedFiles = 0;

            for (let i = 0; i < files.length; i += batchSize) {
                const batch = files.slice(i, i + batchSize);
                for (const file of batch) {
                    if ((file.size ?? 0) <= 0 || isIgnoredSystemFile(file.name)) {
                        continue;
                    }
                    dropzoneInstance.addFile(file as any);
                    queuedFiles++;
                }

                const progress = (queuedFiles / files.length) * 100;
                setUploadProgress(progress, `Queueing: ${queuedFiles}/${files.length}`);
                await new Promise((resolve) => setTimeout(resolve, 0));
            }

            console.log(`Queued ${queuedFiles} files from folder ${folderName}`);
            folderQueueInProgress = false;
            updateFileVisibility();

            // Uploads may already be finished for small folders – show flash now if idle.
            if (
                queuedFiles > 0
                && dropzoneInstance.getQueuedFiles().length === 0
                && dropzoneInstance.getUploadingFiles().length === 0
            ) {
                notifyUploadFinished();
            } else if (dropzoneInstance.getQueuedFiles().length > 0 || dropzoneInstance.getUploadingFiles().length > 0) {
                // Keep progress visible for the remaining uploads.
                setUploadProgress(getOverallUploadProgress(dropzoneInstance));
            } else {
                hideUploadProgress();
            }
            input.value = '';

        } catch (error) {
            console.error('Error queueing folder files:', error);
            folderQueueInProgress = false;
            hideUploadProgress();
            let errorMessage = 'Failed to queue folder files for upload';
            if (error instanceof Error) {
                errorMessage += ': ' + error.message;
            }
            showErrorFlash(errorMessage);
            input.value = '';
        }
    }
});
function checkFormState() {
    const emailSelected = String($('#shared_file_email').val() || '').trim() !== '';
    const userSelected = Boolean($('#shared_file_contact').val());
    const contactEmailSelected = String($('#shared_file_contactEmail').val() || '').trim() !== '';
    const filesUploaded = fileContainer.find('.dz-preview').length > 0;
    const titleFilled = String($('#shared_file_title').val() || '').trim() !== '';
    const messageFilled = String($('#shared_file_message').val() || '').trim() !== '';

    if (filesUploaded && titleFilled && messageFilled && (emailSelected || userSelected || contactEmailSelected)) {
        $('#submitbutton').prop("disabled", false);
        return true;
    }

    $('#submitbutton').prop("disabled", true);
    return false;
}