/**
 * @fileoverview Manages file upload functionality for the room interface.
 * This file handles:
 * - File upload initialization and configuration
 * - Drag and drop file handling
 * - Upload progress tracking
 * - File type validation
 * - Overwrite handling
 * - Batch upload management
 */

/**
 * @class UploadManager
 * @classdesc Manages file upload operations including drag-and-drop, progress tracking,
 * and handling of file conflicts and validations.
 */
export class UploadManager {
    /**
     * Creates a new UploadManager instance.
     * @param {RoomManager} roomManager - The parent RoomManager instance
     */
    constructor(roomManager) {
        this.roomManager = roomManager;
        this.pendingUploads = [];
        this.pendingUploadIdx = 0;
        this.overwriteAll = false;
        this.skipAll = false;
        
        // Initialize upload-related elements
        this.uploadBtn = document.getElementById('uploadBtn');
        this.fileInput = document.getElementById('fileInput');
        this.uploadForm = document.getElementById('uploadForm');
        this.fileGrid = document.getElementById('fileGrid');
        this.dropZoneOverlay = document.getElementById('dropZoneOverlay');
        this.uploadProgressContainer = document.getElementById('uploadProgressContainer');
        this.uploadProgressBar = document.getElementById('uploadProgressBar');
        this.uploadProgressText = document.getElementById('uploadProgressText');
        
        this.initializeUploadHandlers();
    }
    
    /**
     * Initializes event handlers for file upload functionality.
     * Sets up drag and drop handlers and file input change handlers.
     */
    initializeUploadHandlers() {
        if (!this.roomManager.canUpload) return;
        
        // Initialize drag and drop
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            this.fileGrid.addEventListener(eventName, this.preventDefaults.bind(this), false);
            document.body.addEventListener(eventName, this.preventDefaults.bind(this), false);
        });
        
        ['dragenter', 'dragover'].forEach(eventName => {
            this.fileGrid.addEventListener(eventName, this.highlight.bind(this), false);
        });
        
        ['dragleave', 'drop'].forEach(eventName => {
            this.fileGrid.addEventListener(eventName, this.unhighlight.bind(this), false);
        });
        
        // Handle dropped files
        this.fileGrid.addEventListener('drop', this.handleDrop.bind(this), false);
        
        // Handle file input change
        this.uploadBtn.addEventListener('click', () => this.fileInput.click());
        this.fileInput.addEventListener('change', this.handleFileSelect.bind(this));
    }
    
    /**
     * Prevents default browser behavior for drag and drop events.
     * @param {Event} e - The event object
     */
    preventDefaults(e) {
        e.preventDefault();
        e.stopPropagation();
    }
    
    /**
     * Highlights the drop zone when files are dragged over it.
     */
    highlight() {
        this.dropZoneOverlay.style.display = 'block';
    }
    
    /**
     * Removes highlight from the drop zone.
     */
    unhighlight() {
        this.dropZoneOverlay.style.display = 'none';
    }
    
    /**
     * Handles files dropped onto the drop zone.
     * @param {DragEvent} e - The drop event object
     */
    async handleDrop(e) {
        const dt = e.dataTransfer;
        const files = dt.files;
        
        if (files.length > 0) {
            await this.startUpload(Array.from(files));
        }
    }
    
    /**
     * Handles files selected through the file input.
     */
    async handleFileSelect() {
        if (!this.fileInput.files.length) return;
        await this.startUpload(Array.from(this.fileInput.files));
    }
    
    /**
     * Initiates the upload process for a set of files.
     * @param {Array<File>} files - Array of files to upload
     */
    async startUpload(files) {
        this.uploadProgressContainer.style.display = 'block';
        this.uploadProgressBar.style.width = '0%';
        this.uploadProgressBar.className = 'progress-bar bg-primary-opacity-15 text-primary';
        this.uploadProgressText.textContent = '';
        
        this.pendingUploads = files;
        this.pendingUploadIdx = 0;
        this.overwriteAll = false;
        this.skipAll = false;
        
        await this.uploadFilesSequentially();
    }
    
    /**
     * Uploads files one at a time, handling progress and errors.
     * @async
     */
    async uploadFilesSequentially() {
        let completedFiles = 0;
        let currentFileIndex = 0;
        
        const updateProgress = () => {
            if (!this.pendingUploads || currentFileIndex >= this.pendingUploads.length) {
                this.uploadProgressBar.style.width = '100%';
                this.uploadProgressBar.textContent = '100%';
                this.uploadProgressText.textContent = 'Upload complete!';
                return;
            }
            
            const progress = Math.round((completedFiles / this.pendingUploads.length) * 100);
            this.uploadProgressBar.style.width = progress + '%';
            this.uploadProgressBar.textContent = progress + '%';
            this.uploadProgressText.textContent = `Uploading ${this.pendingUploads[currentFileIndex].name} (${currentFileIndex + 1}/${this.pendingUploads.length})`;
        };
        
        const processNextFile = async () => {
            if (currentFileIndex >= this.pendingUploads.length) {
                // All files processed
                this.uploadProgressBar.style.width = '100%';
                this.uploadProgressBar.textContent = '100%';
                this.uploadProgressBar.className = 'progress-bar bg-success-opacity-15 text-success';
                this.uploadProgressText.textContent = 'Upload complete!';
                
                // Reset state
                this.pendingUploads = null;
                this.pendingUploadIdx = null;
                this.overwriteAll = false;
                this.skipAll = false;
                
                // Hide progress after delay
                setTimeout(() => {
                    this.uploadProgressContainer.style.display = 'none';
                    this.uploadProgressText.textContent = '';
                    this.uploadProgressBar.className = 'progress-bar bg-primary-opacity-15 text-primary';
                }, 3000);
                
                // Refresh file list
                await this.roomManager.fileManager.fetchFiles();
                return;
            }
            
            const file = this.pendingUploads[currentFileIndex];
            const formData = new FormData(this.uploadForm);
            if (this.roomManager.currentPath) {
                formData.append('path', this.roomManager.currentPath);
            }
            formData.set('file', file);
            
            try {
                updateProgress();
                
                // If skipAll is true, skip this file
                if (this.skipAll) {
                    console.log('[UploadManager] Skipping file due to skipAll:', file.name);
                    currentFileIndex++;
                    updateProgress();
                    await processNextFile();
                    return;
                }
                
                // If overwriteAll is true, add overwrite flag
                if (this.overwriteAll) {
                    console.log('[UploadManager] Overwriting file due to overwriteAll:', file.name);
                    formData.append('overwrite', 'true');
                }
                
                const response = await this.uploadFile(formData);
                
                if (response.success) {
                    completedFiles++;
                    currentFileIndex++;
                    updateProgress();
                    await processNextFile();
                } else if (response.error === 'File type not allowed') {
                    this.handleFileTypeError(file);
                    currentFileIndex++;
                    updateProgress();
                    await processNextFile();
                } else if (response.error === 'File exists') {
                    // If we have skipAll or overwriteAll set, handle it here
                    if (this.skipAll) {
                        console.log('[UploadManager] Skipping existing file due to skipAll:', file.name);
                        currentFileIndex++;
                        updateProgress();
                        await processNextFile();
                    } else if (this.overwriteAll) {
                        console.log('[UploadManager] Overwriting existing file due to overwriteAll:', file.name);
                        formData.append('overwrite', 'true');
                        await this.uploadFile(formData);
                        completedFiles++;
                        currentFileIndex++;
                        updateProgress();
                        await processNextFile();
                    } else {
                        const result = await this.handleFileExists(file, formData);
                        if (result.continue) {
                            completedFiles++;
                            currentFileIndex++;
                            updateProgress();
                            await processNextFile();
                        }
                    }
                }
            } catch (error) {
                console.error('Upload error:', error);
                this.uploadProgressText.textContent = `Error uploading ${file.name}`;
                this.uploadProgressBar.className = 'progress-bar bg-danger-opacity-15 text-danger';
                currentFileIndex++;
                updateProgress();
                await processNextFile();
            }
        };
        
        await processNextFile();
    }
    
    /**
     * Uploads a single file to the server.
     * @param {FormData} formData - Form data containing the file and upload parameters
     * @returns {Promise<Object>} Response object containing success status and error message if any
     */
    async uploadFile(formData) {
        const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
        const response = await fetch(`/api/rooms/${this.roomManager.roomId}/files/upload`, {
            method: 'POST',
            headers: { 'X-CSRF-Token': csrfToken },
            body: formData
        });
        
        const result = await response.json();
        
        // Handle 409 Conflict response
        if (response.status === 409) {
            return {
                success: false,
                error: 'File exists'
            };
        }
        
        return {
            success: response.ok,
            error: result.error
        };
    }
    
    /**
     * Handles file type validation errors.
     * Displays error message with allowed file types.
     * @param {File} file - The file that failed validation
     */
    handleFileTypeError(file) {
        const allowedTypes = [
            'Documents: PDF, DOCX, DOC, TXT, RTF, ODT, MD, CSV',
            'Spreadsheets: XLSX, XLS, ODS, XLSM',
            'Presentations: PPTX, PPT, ODP',
            'Images: JPG, JPEG, PNG, GIF, BMP, SVG, WEBP, TIFF',
            'Archives: ZIP, RAR, 7Z, TAR, GZ',
            'Code/Text: PY, JS, HTML, CSS, JSON, XML, SQL, SH, BAT',
            'Audio: MP3, WAV, OGG, M4A, FLAC',
            'Video: MP4, AVI, MOV, WMV, FLV, MKV, WEBM',
            'CAD/Design: DWG, DXF, AI, PSD, EPS, INDD',
            'Other: EML, MSG, VCF, ICS'
        ].join('\n');
        
        const uploadError = document.getElementById('uploadError');
        const uploadErrorContent = document.getElementById('uploadErrorContent');
        
        const newError = `<div class="mb-2"><strong>File type not allowed:</strong> ${file.name}</div>`;
        if (uploadErrorContent.innerHTML === '') {
            uploadErrorContent.innerHTML = newError + `<div class='mt-2'><strong>Allowed file types:</strong><br>${allowedTypes}</div>`;
        } else {
            uploadErrorContent.innerHTML = newError + uploadErrorContent.innerHTML;
        }
        
        uploadError.style.display = 'block';
        this.uploadProgressBar.className = 'progress-bar bg-danger-opacity-15 text-danger';
    }
    
    /**
     * Handles file existence conflicts during upload.
     * @param {File} file - The file being uploaded
     * @param {FormData} formData - Form data for the upload
     * @returns {Promise<Object>} Object containing continue status
     */
    async handleFileExists(file, formData) {
        if (this.overwriteAll) {
            formData.append('overwrite', 'true');
            const response = await this.uploadFile(formData);
            return { continue: true };
        }
        
        if (this.skipAll) {
            return { continue: true };
        }
        
        const result = await this.roomManager.modalManager.showOverwriteModal(file.name);
        
        // Add a delay before processing the result
        await new Promise(resolve => setTimeout(resolve, 500));
        
        if (result === 'overwrite' || result === 'overwrite_all') {
            if (result === 'overwrite_all') {
                this.overwriteAll = true;
                this.skipAll = false;
                formData.append('overwrite', 'true');
                await this.uploadFile(formData);
                return { continue: true };
            } else {
                formData.append('overwrite', 'true');
                await this.uploadFile(formData);
                return { continue: true };
            }
        } else if (result === 'skip' || result === 'skip_all') {
            if (result === 'skip_all') {
                this.skipAll = true;
                this.overwriteAll = false;
            }
            return { continue: true };
        }
        
        // If user closes the modal without making a choice, skip the file
        return { continue: true };
    }
} 