<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Epic File Uploader</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.7.14/lottie.min.js"></script>
    <style>
        :root {
            --primary-color: #194898;
            --secondary-color: #4CAF50;
            --background-color: #FFFFFF00;
            --text-color: #333;
            --error-color: #FF6B6B;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body, html {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: var(--background-color);
            color: var(--text-color);
            height: 100%;
            overflow: hidden;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .uploader {
            background-color: white;
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            padding: 20px;
            width: 100%;
            max-width: 500px;
            height: 100%;
            min-height: 200px;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .uploader h2 {
            color: var(--primary-color);
            margin-bottom: 10px;
            font-size: clamp(1rem, 4vw, 1.5rem);
        }

        .drop-zone {
            border: 3px dashed var(--primary-color);
            border-radius: 15px;
            padding: 20px;
            cursor: pointer;
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
            flex-grow: 1;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100px;
            max-height:300px;
        }

        .drop-zone::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: repeating-linear-gradient(
                45deg,
                var(--primary-color),
                var(--primary-color) 10px,
                transparent 10px,
                transparent 20px
            );
            opacity: 0;
            transition: opacity 0.3s ease;
        }

        .drop-zone:hover::before,
        .drop-zone.drag-over::before {
            opacity: 0.1;
        }

        .drop-zone:hover, .drop-zone.drag-over {
            transform: scale(1.02);
        }

        .drop-zone p {
            margin: 0;
            font-size: clamp(0.8rem, 3vw, 1rem);
            color: var(--text-color);
            position: relative;
            z-index: 1;
            text-align: center;
        }

        .file-input {
            display: none;
        }

        .file-list {
            margin-top: 10px;
            overflow-y: auto;
            max-height: 30%;
        }

        .file-item {
            background-color: #f9f9f9;
            border-radius: 10px;
            padding: 10px;
            margin-bottom: 10px;
            font-size: clamp(0.7rem, 2.5vw, 0.9rem);
        }

        .file-info {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
        }

        .file-name {
            font-weight: bold;
            margin-right: 10px;
            display: flex;
            align-items: center;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .file-icon {
            width: 24px;
            height: 24px;
            margin-right: 10px;
            flex-shrink: 0;
        }

        .file-size {
            color: #888;
        }

        .progress-bar {
            height: 5px;
            background-color: #e0e0e0;
            border-radius: 5px;
            overflow: hidden;
        }

        .progress {
            height: 100%;
            background-color: var(--secondary-color);
            width: 0;
            transition: width 0.3s ease;
        }

        .error-message {
            color: var(--error-color);
            font-size: 0.8rem;
            margin-top: 5px;
        }

        .upload-btn {
            background-color: var(--primary-color);
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            font-size: clamp(0.8rem, 3vw, 1rem);
            margin-top: 10px;
            transition: all 0.3s ease;
        }

        .upload-btn:hover {
            background-color: #5A52D5;
        }

        .upload-btn:disabled {
            background-color: #ccc;
            cursor: not-allowed;
        }

        .settings {
            margin-top: 10px;
            font-size: clamp(0.7rem, 2.5vw, 0.9rem);
        }

        .settings label {
            display: block;
            margin-bottom: 5px;
        }

        .settings input {
            width: 100%;
            padding: 5px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: inherit;
        }

        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }

        .uploading .drop-zone {
            animation: pulse 1.5s infinite;
        }

        #completionMessage {
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: var(--secondary-color);
            color: white;
            padding: 10px 20px;
            border-radius: 5px;
            display: none;
            animation: fadeInOut 3s ease-in-out;
            font-size: clamp(0.8rem, 3vw, 1rem);
        }

        @keyframes fadeInOut {
            0%, 100% { opacity: 0; }
            10%, 90% { opacity: 1; }
        }

        .lottie-preview {
            width: 40px;
            height: 40px;
            margin-left: 10px;
        }

        .retry-btn {
            background-color: var(--primary-color);
            color: white;
            border: none;
            padding: 5px 10px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 0.8rem;
            margin-top: 5px;
            transition: all 0.3s ease;
        }

        .retry-btn:hover {
            background-color: #5A52D5;
        }

        @media (max-height: 400px) {
            .uploader {
                flex-direction: row;
                align-items: stretch;
            }

            .drop-zone {
                flex-basis: 50%;
                margin-right: 10px;
            }

            .file-list {
                flex-basis: 50%;
                max-height: none;
                margin-top: 0;
            }

            .upload-btn {
                position: absolute;
                bottom: 10px;
                right: 10px;
            }
        }
    </style>
</head>
<body>
    <div class="uploader" id="uploader">
        <h2>Epic File Uploader</h2>
        <div class="drop-zone" id="dropZone">
            <p>Drag & Drop files here or click to browse</p>
        </div>
        <input type="file" id="fileInput" class="file-input" multiple>
        <div class="file-list" id="fileList"></div>
        <button class="upload-btn" id="uploadBtn" disabled>Upload Files</button>
        <div class="settings" style="display: none;">
            <label for="endpointUrl">Upload Endpoint URL:</label>
            <input type="text" id="endpointUrl" value="https://example.com/upload">
            <label for="allowedTypes">Allowed File Types (comma-separated):</label>
            <input type="text" id="allowedTypes" value="image/*,application/pdf,application/json,.txt,.md">
        </div>
        <label for="debugMode" style="display: flex; align-items: center; margin-top: 10px;">
            <input type="checkbox" id="debugMode"> Debug Mode
        </label>
    </div>
    <div id="completionMessage"></div>

    <script>
        const dropZone = document.getElementById('dropZone');
        const fileInput = document.getElementById('fileInput');
        const fileList = document.getElementById('fileList');
        const uploadBtn = document.getElementById('uploadBtn');
        const uploader = document.getElementById('uploader');
        const endpointUrlInput = document.getElementById('endpointUrl');
        const allowedTypesInput = document.getElementById('allowedTypes');
        const completionMessage = document.getElementById('completionMessage');
        const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
        const debugMode = document.getElementById('debugMode');
        const settings = document.querySelector('.settings');
        let files = [];

        dropZone.addEventListener('click', () => fileInput.click());
        dropZone.addEventListener('dragover', (e) => {
            e.preventDefault();
            dropZone.classList.add('drag-over');
        });
        dropZone.addEventListener('dragleave', () => dropZone.classList.remove('drag-over'));
        dropZone.addEventListener('drop', handleDrop);
        fileInput.addEventListener('change', handleFileSelect);
        uploadBtn.addEventListener('click', uploadFiles);
        debugMode.addEventListener('change', function() {
            settings.style.display = this.checked ? 'block' : 'none';
        });

        function handleDrop(e) {
            e.preventDefault();
            dropZone.classList.remove('drag-over');
            const droppedFiles = e.dataTransfer.files;
            handleFiles(droppedFiles);
        }

        function handleFileSelect(e) {
            const selectedFiles = e.target.files;
            handleFiles(selectedFiles);
        }

        function handleFiles(newFiles) {
            const allowedTypes = allowedTypesInput.value.split(',').map(type => type.trim());
            const filteredFiles = Array.from(newFiles).filter(file => {
                const isAllowedType = allowedTypes.some(type => {
                    if (type.endsWith('/*')) {
                        return file.type.startsWith(type.slice(0, -2));
                    }
                    if (type.startsWith('.')) {
                        return file.name.toLowerCase().endsWith(type.toLowerCase());
                    }
                    return file.type === type || type === '*';
                });
                const isAllowedSize = file.size <= MAX_FILE_SIZE;
                if (!isAllowedType) {
                    console.warn(`File ${file.name} is not an allowed type.`);
                }
                if (!isAllowedSize) {
                    console.warn(`File ${file.name} exceeds the maximum size of 5MB.`);
                }
                return isAllowedType && isAllowedSize;
            });

            files = [...files, ...filteredFiles];
            updateFileList();
            uploadBtn.disabled = files.length === 0;

            // Post message for selected files
            window.parent.postMessage({
                type: 'filesSelected',
                files: files.map(file => ({
                    name: file.name,
                    type: file.type,
                    size: file.size
                }))
            }, '*');
        }

        function updateFileList() {
            fileList.innerHTML = '';
            files.forEach((file, index) => {
                const fileItem = document.createElement('div');
                fileItem.className = 'file-item';
                const fileIcon = getFileIcon(file.type);
                fileItem.innerHTML = `
                    <div class="file-info">
                        <span class="file-name">
                            <img src="${fileIcon}" class="file-icon" alt="File icon">
                            ${file.name}
                        </span>
                        <span class="file-size">${formatFileSize(file.size)}</span>
                    </div>
                    <div class="progress-bar">
                        <div class="progress" id="progress-${index}"></div>
                    </div>
                    <div class="error-message" id="error-${index}"></div>
                    <button class="retry-btn" id="retry-${index}" style="display: none;">Retry</button>
                `;
                if (file.name.endsWith('.json')) {
                    const previewContainer = document.createElement('div');
                    previewContainer.className = 'lottie-preview';
                    previewContainer.id = `lottie-preview-${index}`;
                    fileItem.appendChild(previewContainer);
                    loadLottiePreview(file, previewContainer);
                }
                fileList.appendChild(fileItem);

                // Add event listener for retry button
                const retryBtn = document.getElementById(`retry-${index}`);
                retryBtn.addEventListener('click', () => retryUpload(file, index));
            });
        }

        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }

        function getFileIcon(fileType) {
            const iconMap = {
                'image': 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath fill="%236C63FF" d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 16H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zM8 10l2.5 3.01L12.5 11l3.5 4H8v-5z"/%3E%3C/svg%3E',
                'application/pdf': 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath fill="%23FF5722" d="M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 7.5c0 .83-.67 1.5-1.5 1.5H9v2H7.5V7H10c.83 0 1.5.67 1.5 1.5v1zm5 2c0 .83-.67 1.5-1.5 1.5h-2.5V7H15c.83 0 1.5.67 1.5 1.5v3zm4-3H19v1h1.5V11H19v2h-1.5V7h3v1.5zM9 9.5h1v-1H9v1zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm10 5.5h1v-3h-1v3z"/%3E%3C/svg%3E',
                'application/json': 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath fill="%23FFC107" d="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9 18c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm0-3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm3 3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm0-3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm3 3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm0-3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/%3E%3C/svg%3E',
                'default': 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath fill="%239E9E9E" d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6z"/%3E%3C/svg%3E'
            };
            const fileCategory = fileType.split('/')[0];
            return iconMap[fileType] || iconMap[fileCategory] || iconMap['default'];
        }

        function loadLottiePreview(file, container) {
            const reader = new FileReader();
            reader.onload = function(e) {
                try {
                    const jsonData = JSON.parse(e.target.result);
                    lottie.loadAnimation({
                        container: container,
                        renderer: 'svg',
                        loop: true,
                        autoplay: true,
                        animationData: jsonData
                    });
                } catch (error) {
                    console.error('Error loading Lottie animation:', error);
                }
            };
            reader.readAsText(file);
        }

        async function uploadFiles() {
            uploader.classList.add('uploading');
            uploadBtn.disabled = true;

            let completedUploads = 0;
            let failedUploads = 0;

            const fileContents = await Promise.all(files.map(readFileAsArrayBuffer));

            // Post message for upload start with file contents
            window.parent.postMessage({
                type: 'uploadStarted',
                files: files.map((file, index) => ({
                    name: file.name,
                    type: file.type,
                    size: file.size,
                    content: fileContents[index]
                }))
            }, '*');

            files.forEach((file, index) => {
                uploadFileInChunks(file, index);
            });
        }

        function uploadFileInChunks(file, index) {
            const CHUNK_SIZE = 1024 * 1024; // 1MB chunks
            const chunks = Math.ceil(file.size / CHUNK_SIZE);
            let chunkIndex = 0;

            function uploadNextChunk() {
                const start = chunkIndex * CHUNK_SIZE;
                const end = Math.min(start + CHUNK_SIZE, file.size);
                const chunk = file.slice(start, end);

                const xhr = new XMLHttpRequest();
                const formData = new FormData();
                formData.append('file', chunk, file.name);
                formData.append('chunk', chunkIndex);
                formData.append('chunks', chunks);

                xhr.open('POST', endpointUrlInput.value, true);
                xhr.upload.onprogress = (event) => {
                    if (event.lengthComputable) {
                        const totalProgress = ((chunkIndex + (event.loaded / event.total)) / chunks) * 100;
                        updateProgress(index, totalProgress);
                    }
                };

                xhr.onload = function() {
                    if (xhr.status === 200) {
                        chunkIndex++;
                        if (chunkIndex < chunks) {
                            uploadNextChunk();
                        } else {
                            console.log(`File ${file.name} uploaded successfully`);
                            completedUploads++;
                            checkUploadCompletion();
                        }
                    } else {
                        console.error(`Error uploading chunk ${chunkIndex} of file ${file.name}: ${xhr.statusText}`);
                        showError(index, `Upload failed: ${xhr.statusText}`);
                        failedUploads++;
                        checkUploadCompletion();
                    }
                };

                xhr.onerror = function() {
                    console.error(`Network error occurred while uploading chunk ${chunkIndex} of file ${file.name}`);
                    showError(index, 'Network error occurred');
                    failedUploads++;
                    checkUploadCompletion();
                };

                xhr.send(formData);
            }

            uploadNextChunk();
        }

        function updateProgress(index, percent) {
            const progressBar = document.getElementById(`progress-${index}`);
            progressBar.style.width = `${percent}%`;
        }

        function showError(index, message) {
            const errorElement = document.getElementById(`error-${index}`);
            const retryBtn = document.getElementById(`retry-${index}`);
            errorElement.textContent = message;
            if (message) {
                retryBtn.style.display = 'inline-block';
            } else {
                retryBtn.style.display = 'none';
            }
        }

        function retryUpload(file, index) {
            showError(index, '');
            updateProgress(index, 0);
            document.getElementById(`retry-${index}`).style.display = 'none';
            uploadFileInChunks(file, index);
        }

        function checkUploadCompletion() {
            if (completedUploads + failedUploads === files.length) {
                finishUpload(completedUploads, failedUploads);
            }
        }

        function finishUpload(completed, failed) {
            uploader.classList.remove('uploading');
            uploadBtn.disabled = false;
            
            const totalFiles = files.length;
            const message = `Upload complete: ${completed} of ${totalFiles} files uploaded successfully. ${failed} files failed.`;
            
            completionMessage.textContent = message;
            completionMessage.style.display = 'block';
            
            setTimeout(() => {
                completionMessage.style.display = 'none';
            }, 3000);

            files = [];
            updateFileList();
        }

        function readFileAsArrayBuffer(file) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = event => resolve(event.target.result);
                reader.onerror = error => reject(error);
                reader.readAsArrayBuffer(file);
            });
        }
    </script>
</body>
</html>

