/**
 * Smart File Upload System
 * Handles immediate file uploads via AJAX to prevent data loss on validation errors
 * Author: CLS Instructors System
 * Version: 1.0.0
 */

class SmartFileUpload {
    constructor(inputElement, options = {}) {
        this.input = inputElement;
        this.options = {
            uploadUrl: options.uploadUrl || '/admin/upload-temp-file',
            maxSize: options.maxSize || 10 * 1024 * 1024, // 10MB default
            acceptedTypes: options.acceptedTypes || null,
            allowMultiple: options.allowMultiple || false,
            onUploadStart: options.onUploadStart || null,
            onUploadSuccess: options.onUploadSuccess || null,
            onUploadError: options.onUploadError || null,
            onFileRemove: options.onFileRemove || null,
            ...options
        };

        this.uploadedFiles = [];
        this.init();
    }

    init() {
        this.createUIElements();
        this.attachEventListeners();
        this.checkForOldFiles();
    }

    createUIElements() {
        // Create container for status messages
        this.statusContainer = document.createElement('div');
        this.statusContainer.className = 'smart-upload-status mt-2';
        
        // Create progress bar
        this.progressBar = document.createElement('div');
        this.progressBar.className = 'progress d-none mt-2';
        this.progressBar.style.height = '20px';
        this.progressBar.innerHTML = `
            <div class="progress-bar progress-bar-striped progress-bar-animated" 
                 role="progressbar" 
                 style="width: 0%">0%</div>
        `;
        
        // Create file list container
        this.fileListContainer = document.createElement('div');
        this.fileListContainer.className = 'uploaded-files-list mt-2';
        
        // Insert after the input
        this.input.parentNode.insertBefore(this.statusContainer, this.input.nextSibling);
        this.input.parentNode.insertBefore(this.progressBar, this.statusContainer.nextSibling);
        this.input.parentNode.insertBefore(this.fileListContainer, this.progressBar.nextSibling);

        // Create hidden input for storing uploaded file data
        this.hiddenInput = document.createElement('input');
        this.hiddenInput.type = 'hidden';
        this.hiddenInput.name = this.input.name + '_uploaded';
        this.hiddenInput.id = this.input.id + '_uploaded';
        this.input.parentNode.insertBefore(this.hiddenInput, this.fileListContainer.nextSibling);
    }

    attachEventListeners() {
        this.input.addEventListener('change', (e) => this.handleFileSelection(e));
    }

    checkForOldFiles() {
        // Check if there are old files from previous submission (validation error)
        const oldFilesInput = document.getElementById(this.input.name + '_old');
        if (oldFilesInput && oldFilesInput.value) {
            try {
                const oldFiles = JSON.parse(oldFilesInput.value);
                if (Array.isArray(oldFiles) && oldFiles.length > 0) {
                    oldFiles.forEach(file => {
                        this.uploadedFiles.push(file);
                        this.displayUploadedFile(file, true);
                    });
                    this.updateHiddenInput();
                }
            } catch (e) {
                console.error('Error parsing old files:', e);
            }
        }
    }

    async handleFileSelection(e) {
        const files = Array.from(e.target.files);
        
        if (files.length === 0) return;

        // Clear previous uploads if not multiple
        if (!this.options.allowMultiple) {
            this.clearUploadedFiles();
        }

        for (const file of files) {
            // Validate file
            const validation = this.validateFile(file);
            if (!validation.valid) {
                this.showError(validation.message);
                continue;
            }

            // Upload file
            await this.uploadFile(file);
        }

        // Clear the input so the same file can be selected again if needed
        e.target.value = '';
    }

    validateFile(file) {
        // Check file size
        if (this.options.maxSize && file.size > this.options.maxSize) {
            return {
                valid: false,
                message: `File size exceeds maximum allowed size of ${this.formatBytes(this.options.maxSize)}`
            };
        }

        // Check file type
        if (this.options.acceptedTypes) {
            const types = this.options.acceptedTypes.split(',').map(t => t.trim());
            const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
            const mimeType = file.type;
            
            const isValidType = types.some(type => {
                if (type.startsWith('.')) {
                    return fileExtension === type.toLowerCase();
                } else {
                    return mimeType.match(new RegExp(type.replace('*', '.*')));
                }
            });

            if (!isValidType) {
                return {
                    valid: false,
                    message: `File type not allowed. Accepted types: ${this.options.acceptedTypes}`
                };
            }
        }

        return { valid: true };
    }

    async uploadFile(file) {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('field_name', this.input.name);

        // Get CSRF token
        const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
        if (csrfToken) {
            formData.append('_token', csrfToken);
        }

        // Show progress bar
        this.showProgress(0);
        
        if (this.options.onUploadStart) {
            this.options.onUploadStart(file);
        }

        try {
            const xhr = new XMLHttpRequest();

            // Track upload progress
            xhr.upload.addEventListener('progress', (e) => {
                if (e.lengthComputable) {
                    const percentComplete = Math.round((e.loaded / e.total) * 100);
                    this.updateProgress(percentComplete);
                }
            });

            // Handle completion
            xhr.addEventListener('load', () => {
                if (xhr.status === 200) {
                    try {
                        const response = JSON.parse(xhr.responseText);
                        if (response.success) {
                            this.uploadedFiles.push(response.file);
                            this.displayUploadedFile(response.file);
                            this.updateHiddenInput();
                            this.showSuccess(`File "${file.name}" uploaded successfully!`);
                            
                            if (this.options.onUploadSuccess) {
                                this.options.onUploadSuccess(response.file, file);
                            }
                        } else {
                            this.showError(response.message || 'Upload failed');
                            
                            if (this.options.onUploadError) {
                                this.options.onUploadError(response.message, file);
                            }
                        }
                    } catch (e) {
                        this.showError('Error processing upload response');
                        console.error('Upload response error:', e);
                    }
                } else {
                    this.showError(`Upload failed with status: ${xhr.status}`);
                }
                this.hideProgress();
            });

            // Handle errors
            xhr.addEventListener('error', () => {
                this.showError('Network error during upload');
                this.hideProgress();
                
                if (this.options.onUploadError) {
                    this.options.onUploadError('Network error', file);
                }
            });

            // Send request
            xhr.open('POST', this.options.uploadUrl, true);
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.send(formData);

        } catch (error) {
            this.showError('Upload error: ' + error.message);
            this.hideProgress();
            console.error('Upload error:', error);
        }
    }

    displayUploadedFile(fileData, isOld = false) {
        const fileItem = document.createElement('div');
        fileItem.className = 'alert alert-success alert-dismissible fade show d-flex align-items-center justify-content-between';
        fileItem.style.padding = '8px 12px';
        fileItem.dataset.tempPath = fileData.temp_path;
        
        const fileIcon = this.getFileIcon(fileData.original_name);
        
        fileItem.innerHTML = `
            <div class="d-flex align-items-center flex-grow-1">
                <i class="${fileIcon} me-2"></i>
                <div>
                    <strong>${fileData.original_name}</strong>
                    <small class="text-muted d-block">${this.formatBytes(fileData.size)} ${isOld ? '(Previously uploaded)' : '(Just uploaded)'}</small>
                </div>
            </div>
            <button type="button" class="btn-close" aria-label="Close"></button>
        `;

        const closeBtn = fileItem.querySelector('.btn-close');
        closeBtn.addEventListener('click', () => {
            this.removeUploadedFile(fileData.temp_path);
            fileItem.remove();
        });

        this.fileListContainer.appendChild(fileItem);
    }

    removeUploadedFile(tempPath) {
        this.uploadedFiles = this.uploadedFiles.filter(f => f.temp_path !== tempPath);
        this.updateHiddenInput();
        
        if (this.options.onFileRemove) {
            this.options.onFileRemove(tempPath);
        }

        // Optionally send delete request to server
        this.deleteFileFromServer(tempPath);
    }

    async deleteFileFromServer(tempPath) {
        try {
            const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
            
            await fetch('/admin/delete-temp-file', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': csrfToken,
                    'X-Requested-With': 'XMLHttpRequest'
                },
                body: JSON.stringify({ temp_path: tempPath })
            });
        } catch (error) {
            console.error('Error deleting temp file:', error);
        }
    }

    clearUploadedFiles() {
        this.uploadedFiles.forEach(file => {
            this.deleteFileFromServer(file.temp_path);
        });
        this.uploadedFiles = [];
        this.fileListContainer.innerHTML = '';
        this.updateHiddenInput();
    }

    updateHiddenInput() {
        this.hiddenInput.value = JSON.stringify(this.uploadedFiles);
    }

    showProgress(percent) {
        this.progressBar.classList.remove('d-none');
        this.updateProgress(percent);
    }

    updateProgress(percent) {
        const bar = this.progressBar.querySelector('.progress-bar');
        bar.style.width = percent + '%';
        bar.textContent = percent + '%';
    }

    hideProgress() {
        setTimeout(() => {
            this.progressBar.classList.add('d-none');
        }, 1000);
    }

    showSuccess(message) {
        this.showMessage(message, 'success');
    }

    showError(message) {
        this.showMessage(message, 'danger');
    }

    showMessage(message, type = 'info') {
        const alert = document.createElement('div');
        alert.className = `alert alert-${type} alert-dismissible fade show`;
        alert.innerHTML = `
            ${message}
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        `;
        
        this.statusContainer.appendChild(alert);
        
        // Auto-dismiss after 5 seconds
        setTimeout(() => {
            alert.remove();
        }, 5000);
    }

    getFileIcon(filename) {
        const extension = filename.split('.').pop().toLowerCase();
        const iconMap = {
            'pdf': 'bi bi-file-earmark-pdf-fill text-danger',
            'doc': 'bi bi-file-earmark-word-fill text-primary',
            'docx': 'bi bi-file-earmark-word-fill text-primary',
            'xls': 'bi bi-file-earmark-excel-fill text-success',
            'xlsx': 'bi bi-file-earmark-excel-fill text-success',
            'jpg': 'bi bi-file-earmark-image-fill text-info',
            'jpeg': 'bi bi-file-earmark-image-fill text-info',
            'png': 'bi bi-file-earmark-image-fill text-info',
            'gif': 'bi bi-file-earmark-image-fill text-info',
            'zip': 'bi bi-file-earmark-zip-fill text-warning',
            'rar': 'bi bi-file-earmark-zip-fill text-warning',
            'mp4': 'bi bi-file-earmark-play-fill text-purple',
            'avi': 'bi bi-file-earmark-play-fill text-purple',
            'mp3': 'bi bi-file-earmark-music-fill text-purple',
            'wav': 'bi bi-file-earmark-music-fill text-purple',
            'opus': 'bi bi-file-earmark-music-fill text-purple'
        };
        
        return iconMap[extension] || 'bi bi-file-earmark-fill text-secondary';
    }

    formatBytes(bytes, decimals = 2) {
        if (bytes === 0) return '0 Bytes';
        
        const k = 1024;
        const dm = decimals < 0 ? 0 : decimals;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        
        return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
    }
}

// Initialize all smart upload inputs on page load
document.addEventListener('DOMContentLoaded', function() {
    const smartUploadInputs = document.querySelectorAll('[data-smart-upload="true"]');
    
    smartUploadInputs.forEach(input => {
        const options = {
            uploadUrl: input.dataset.uploadUrl || '/admin/upload-temp-file',
            maxSize: input.dataset.maxSize ? parseInt(input.dataset.maxSize) : 10 * 1024 * 1024,
            acceptedTypes: input.dataset.acceptedTypes || input.accept || null,
            allowMultiple: input.hasAttribute('multiple')
        };
        
        new SmartFileUpload(input, options);
    });
});

// Export for use in other scripts
if (typeof module !== 'undefined' && module.exports) {
    module.exports = SmartFileUpload;
}

