/**
 * OxiCloud Inline Viewer
 * A simpler approach to viewing files that doesn't rely on complex DOM manipulation
 */

import { updateHistory } from '../../app/main.js';
import { app } from '../../app/state.js';
import { isTextViewable } from '../../core/formatters.js';
import { wopiEditor } from './wopiEditor.js';

class InlineViewer {
    constructor() {
        this.setupViewer();
        this.currentFile = null;
    }

    setupViewer() {
        // Create the viewer modal if it doesn't exist
        if (document.getElementById('inline-viewer-modal')) {
            return;
        }

        // Verify document.body exists
        if (!document.body) {
            console.warn('Document body not available yet for inline viewer, will retry later');
            setTimeout(() => this.setupViewer(), 200);
            return;
        }

        // Create modal container
        const modal = document.createElement('div');
        modal.id = 'inline-viewer-modal';
        modal.className = 'inline-viewer-modal';
        modal.innerHTML = `
      <div class="inline-viewer-content">
        <div class="inline-viewer-header">
          <div class="inline-viewer-title">File Viewer</div>
          <button class="inline-viewer-close"><i class="fas fa-times"></i></button>
        </div>
        <div class="inline-viewer-container"></div>
        <div class="inline-viewer-toolbar">
          <button class="inline-viewer-download"><i class="fas fa-download"></i> Download</button>
          <div class="inline-viewer-controls">
            <button class="inline-viewer-zoom-out" title="Zoom Out"><i class="fas fa-search-minus"></i></button>
            <button class="inline-viewer-zoom-reset" title="Reset Zoom"><i class="fas fa-expand"></i></button>
            <button class="inline-viewer-zoom-in" title="Zoom In"><i class="fas fa-search-plus"></i></button>
          </div>
        </div>
      </div>
    `;

        // Add to document
        document.body.appendChild(modal);

        // Add event listeners
        modal.querySelector('.inline-viewer-close').addEventListener('click', () => {
            this.closeViewer();
        });

        modal.querySelector('.inline-viewer-download').addEventListener('click', () => {
            if (this.currentFile) {
                this.downloadFile(this.currentFile);
            }
        });

        // Add zoom controls for images
        modal.querySelector('.inline-viewer-zoom-in').addEventListener('click', () => {
            this.zoomImage(1.2);
        });

        modal.querySelector('.inline-viewer-zoom-out').addEventListener('click', () => {
            this.zoomImage(0.8);
        });

        modal.querySelector('.inline-viewer-zoom-reset').addEventListener('click', () => {
            this.resetZoom();
        });

        // Close on ESC key
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && modal.classList.contains('active')) {
                this.closeViewer();
            }
        });

        // Click outside to close
        modal.addEventListener('click', (e) => {
            if (e.target === modal) {
                this.closeViewer();
            }
        });

        console.log('Inline viewer initialized');
    }

    async openFile(file) {
        console.log('Opening file:', file);

        // WOPI editor intercept: open Office documents in the WOPI editor
        // But NOT image files - those should be previewed in the inline viewer
        // Detect images by mime type OR extension (uploads via WebDAV may lack correct mime)
        const ext = (file.name || '').split('.').pop().toLowerCase();
        const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'ico', 'heic', 'heif', 'avif', 'tiff'];
        const isImage = file.mime_type?.startsWith('image/') || imageExts.includes(ext);
        if (!isImage && wopiEditor && (await wopiEditor.canEdit(file.name))) {
            try {
                wopiEditor.openInModal(file.id, file.name, 'edit');
                return;
            } catch (e) {
                console.warn('WOPI editor failed, falling back to inline viewer:', e);
            }
        }

        this.currentFile = file;

        // Get container
        const modal = document.getElementById('inline-viewer-modal');
        const container = modal.querySelector('.inline-viewer-container');
        const title = modal.querySelector('.inline-viewer-title');

        // Clear container
        container.innerHTML = '';

        // Set title
        title.textContent = file.name;

        // Set controls visibility
        const controls = modal.querySelector('.inline-viewer-controls');

        // Show viewer based on file type
        if (isImage) {
            // Show zoom controls
            controls.style.display = 'flex';

            // Show loading indicator
            const loader = document.createElement('div');
            loader.className = 'inline-viewer-loader';
            loader.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
            container.appendChild(loader);

            // Create image viewer using a blob URL
            this.createBlobUrlViewer(file, 'image', container, loader);
        } else if (file.mime_type && file.mime_type === 'application/pdf') {
            // Hide zoom controls for PDFs
            controls.style.display = 'none';

            // Show loading indicator
            const loader = document.createElement('div');
            loader.className = 'inline-viewer-loader';
            loader.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
            container.appendChild(loader);

            // Create PDF viewer using object tag with blob URL
            this.createBlobUrlViewer(file, 'pdf', container, loader);
        } else if (file.mime_type && this.isTextViewable(file.mime_type)) {
            // Hide zoom controls for text files
            controls.style.display = 'none';

            // Show loading indicator
            const loader = document.createElement('div');
            loader.className = 'inline-viewer-loader';
            loader.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
            container.appendChild(loader);

            // Create text viewer using authenticated fetch
            this.createTextViewer(file, container, loader);
        } else if (file.mime_type?.startsWith('audio/')) {
            // Hide zoom controls for audio
            controls.style.display = 'none';

            // Show loading indicator
            const loader = document.createElement('div');
            loader.className = 'inline-viewer-loader';
            loader.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
            container.appendChild(loader);

            // Create audio player
            this.createMediaViewer(file, 'audio', container, loader);
        } else if (file.mime_type?.startsWith('video/')) {
            // Hide zoom controls for video
            controls.style.display = 'none';

            // Show loading indicator
            const loader = document.createElement('div');
            loader.className = 'inline-viewer-loader';
            loader.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
            container.appendChild(loader);

            // Create video player
            this.createMediaViewer(file, 'video', container, loader);
        } else {
            // Hide zoom controls for unsupported files
            controls.style.display = 'none';

            // Show unsupported file message
            const message = document.createElement('div');
            message.className = 'inline-viewer-message';
            message.innerHTML = `
        <div class="inline-viewer-icon"><i class="fas fa-file"></i></div>
        <div class="inline-viewer-text">
          <p>This file type cannot be previewed.</p>
          <p>Click "Download" to get the file.</p>
        </div>
      `;
            container.appendChild(message);
        }

        // Show modal
        modal.classList.add('active');
    }

    // Check if a MIME type is text-viewable
    isTextViewable(mimeType) {
        return isTextViewable(mimeType);
    }

    // Creates a text viewer using authenticated fetch
    async createTextViewer(file, container, loader) {
        try {
            console.log('Creating text viewer for:', file.name);

            const response = await fetch(`/api/files/${file.id}?inline=true`, {
                credentials: 'same-origin'
            });

            if (!response.ok) {
                throw new Error(`Error fetching file: ${response.status} ${response.statusText}`);
            }

            const text = await response.text();

            // Remove loader
            if (loader?.parentNode) {
                loader.parentNode.removeChild(loader);
            }

            // Create text viewer element
            const pre = document.createElement('pre');
            pre.className = 'inline-viewer-text-content';
            pre.textContent = text;
            container.appendChild(pre);

            console.log('Text viewer created successfully');
        } catch (error) {
            console.error('Error creating text viewer:', error);

            // Remove loader
            if (loader?.parentNode) {
                loader.parentNode.removeChild(loader);
            }

            this.showErrorMessage(container);
        }
    }

    // Creates a viewer using a Blob URL to avoid content-disposition header
    async createBlobUrlViewer(file, type, container, loader) {
        try {
            console.log('Creating blob URL viewer for:', file.name, 'type:', type);

            // Update loader to show progress bar for large files
            let progressBar = null;
            let progressText = null;
            if (loader && file.size > 10 * 1024 * 1024) {
                // Show progress for files > 10MB
                loader.innerHTML = `
          <div class="inline-viewer-progress">
            <i class="fas fa-spinner fa-spin"></i>
            <div class="inline-viewer-progress-bar">
              <div class="inline-viewer-progress-fill" style="width: 0%"></div>
            </div>
            <div class="inline-viewer-progress-text">0%</div>
          </div>
        `;
                progressBar = loader.querySelector('.inline-viewer-progress-fill');
                progressText = loader.querySelector('.inline-viewer-progress-text');
            }

            // Use XMLHttpRequest instead of fetch to get better control over the response
            const xhr = new XMLHttpRequest();
            xhr.open('GET', `/api/files/${file.id}?inline=true`, true);
            xhr.responseType = 'blob';
            xhr.withCredentials = true;

            // Track download progress - use double precision for large file support (>2GB)
            xhr.onprogress = (e) => {
                if (e.lengthComputable && progressBar && progressText) {
                    // Use direct division to avoid 32-bit overflow issues
                    // e.loaded and e.total are JavaScript numbers (64-bit float)
                    const progress = e.loaded / e.total;
                    const pct = Math.round(progress * 100);
                    progressBar.style.width = `${pct}%`;
                    progressText.textContent = `${pct}%`;
                }
            };

            // Create a promise to handle the XHR
            const response = await new Promise((resolve, reject) => {
                xhr.onload = function () {
                    if (this.status >= 200 && this.status < 300) {
                        resolve(this.response);
                    } else {
                        reject(new Error(`Error fetching file: ${this.status} ${this.statusText}`));
                    }
                };

                xhr.onerror = () => {
                    reject(new Error('Network error'));
                };

                xhr.send();
            });

            // Create blob URL from response
            const blob = response;
            const blobUrl = URL.createObjectURL(blob);

            console.log('Created blob URL:', `${blobUrl.substring(0, 30)}...`);

            // Remove loader
            if (loader?.parentNode) {
                loader.parentNode.removeChild(loader);
            }

            if (type === 'image') {
                console.log('Creating image viewer');
                // Create image element
                const img = document.createElement('img');
                img.className = 'inline-viewer-image';
                img.src = blobUrl;
                img.alt = file.name;
                container.appendChild(img);

                // Add loading indicator until image loads
                img.style.opacity = 0;
                img.onload = () => {
                    console.log('Image loaded successfully');
                    img.style.opacity = 1;
                };

                img.onerror = () => {
                    console.error('Failed to load image');
                    container.removeChild(img);
                    this.showErrorMessage(container);
                };
            } else if (type === 'pdf') {
                console.log('Creating PDF viewer');

                // Create iframe for PDF (more reliable than object tag)
                const iframe = document.createElement('iframe');
                iframe.className = 'inline-viewer-pdf';
                iframe.src = blobUrl;
                iframe.setAttribute('allowfullscreen', 'true');
                container.appendChild(iframe);

                // Monitor iframe for loading issues
                setTimeout(() => {
                    if (!iframe.contentDocument || iframe.contentDocument.body.innerHTML === '') {
                        console.warn('PDF viewer might be having issues, adding fallback');

                        // Add fallback embed
                        const embed = document.createElement('embed');
                        embed.className = 'inline-viewer-pdf-fallback';
                        embed.type = 'application/pdf';
                        embed.src = blobUrl;
                        container.appendChild(embed);
                    }
                }, 2000);
            }

            // Store blob URL for cleaning up later
            this.currentBlobUrl = blobUrl;
        } catch (error) {
            console.error('Error creating blob URL viewer:', error);

            // Remove loader
            if (loader?.parentNode) {
                loader.parentNode.removeChild(loader);
            }

            this.showErrorMessage(container);
        }
    }

    // Creates an audio or video player using blob URL (authenticated fetch)
    async createMediaViewer(file, mediaType, container, loader) {
        try {
            console.log(`Creating ${mediaType} player for:`, file.name);

            // Fetch file (cookie auto-sent)
            const response = await fetch(`/api/files/${file.id}?inline=true`, {
                credentials: 'same-origin'
            });

            if (!response.ok) {
                throw new Error(`Error fetching file: ${response.status} ${response.statusText}`);
            }

            const blob = await response.blob();
            const blobUrl = URL.createObjectURL(blob);

            // Remove loader
            if (loader?.parentNode) {
                loader.parentNode.removeChild(loader);
            }

            if (mediaType === 'audio') {
                // Wrapper with icon + player
                const wrapper = document.createElement('div');
                wrapper.className = 'inline-viewer-audio-wrapper';

                const icon = document.createElement('div');
                icon.className = 'inline-viewer-audio-icon';
                icon.innerHTML = '<i class="fas fa-music"></i>';
                wrapper.appendChild(icon);

                const nameEl = document.createElement('div');
                nameEl.className = 'inline-viewer-audio-name';
                nameEl.textContent = file.name;
                wrapper.appendChild(nameEl);

                const audio = document.createElement('audio');
                audio.className = 'inline-viewer-audio';
                audio.controls = true;
                audio.preload = 'metadata';
                audio.src = blobUrl;
                wrapper.appendChild(audio);

                // Fallback message for unsupported codecs
                audio.addEventListener('error', () => {
                    console.warn('Audio playback error — codec may not be supported');
                    wrapper.innerHTML = '';
                    const msg = document.createElement('div');
                    msg.className = 'inline-viewer-message';
                    msg.innerHTML = `
            <div class="inline-viewer-icon"><i class="fas fa-exclamation-circle"></i></div>
            <div class="inline-viewer-text">
              <p>Your browser cannot play this audio format.</p>
              <p>Click "Download" to save the file.</p>
            </div>
          `;
                    wrapper.appendChild(msg);
                });

                container.appendChild(wrapper);
            } else {
                const video = document.createElement('video');
                video.className = 'inline-viewer-video';
                video.controls = true;
                video.preload = 'metadata';
                video.src = blobUrl;
                video.setAttribute('playsinline', 'true');

                // Fallback message for unsupported codecs
                video.addEventListener('error', () => {
                    console.warn('Video playback error — codec may not be supported');
                    if (video.parentNode) {
                        video.parentNode.removeChild(video);
                    }
                    const msg = document.createElement('div');
                    msg.className = 'inline-viewer-message';
                    msg.innerHTML = `
            <div class="inline-viewer-icon"><i class="fas fa-exclamation-circle"></i></div>
            <div class="inline-viewer-text">
              <p>Your browser cannot play this video format.</p>
              <p>Click "Download" to save the file.</p>
            </div>
          `;
                    container.appendChild(msg);
                });

                container.appendChild(video);
            }

            // Store blob URL for cleanup on close
            this.currentBlobUrl = blobUrl;
        } catch (error) {
            console.error(`Error creating ${mediaType} viewer:`, error);

            if (loader?.parentNode) {
                loader.parentNode.removeChild(loader);
            }

            this.showErrorMessage(container);
        }
    }

    // Helper to show error message
    showErrorMessage(container) {
        // Show error message
        const message = document.createElement('div');
        message.className = 'inline-viewer-message';
        message.innerHTML = `
      <div class="inline-viewer-icon"><i class="fas fa-exclamation-triangle"></i></div>
      <div class="inline-viewer-text">
        <p>Error loading the file.</p>
        <p>Try downloading it directly.</p>
      </div>
    `;
        container.appendChild(message);
    }

    closeViewer() {
        // Get modal
        const modal = document.getElementById('inline-viewer-modal');

        // stops audio/video before closing viewver
        const media = modal.querySelector('audio, video');
        if (media && !media.paused) media.pause();

        // Hide modal
        modal.classList.remove('active');

        // Clean up blob URL if exists
        if (this.currentBlobUrl) {
            URL.revokeObjectURL(this.currentBlobUrl);
            this.currentBlobUrl = null;
        }

        // clear
        app.viewFile = null;
        updateHistory(false);

        // Clear references
        this.currentFile = null;
    }

    downloadFile(file) {
        fetch(`/api/files/${file.id}`, { credentials: 'same-origin' })
            .then((res) => {
                if (!res.ok) throw new Error(`HTTP ${res.status}`);
                return res.blob();
            })
            .then((blob) => {
                const url = URL.createObjectURL(blob);
                const link = document.createElement('a');
                link.href = url;
                link.download = file.name;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(url);
            })
            .catch((err) => console.error('Download error:', err));
    }

    zoomImage(factor) {
        const container = document.querySelector('.inline-viewer-container');
        const img = container.querySelector('.inline-viewer-image');

        if (!img) return;

        // Get current scale
        let scale = img.dataset.scale ? parseFloat(img.dataset.scale) : 1.0;

        // Apply zoom factor
        scale *= factor;

        // Limit scale
        scale = Math.max(0.1, Math.min(5.0, scale));

        // Save scale
        img.dataset.scale = scale;

        // Apply scale
        img.style.transform = `scale(${scale})`;
    }

    resetZoom() {
        const container = document.querySelector('.inline-viewer-container');
        const img = container.querySelector('.inline-viewer-image');

        if (!img) return;

        // Reset scale
        img.dataset.scale = 1.0;
        img.style.transform = 'scale(1.0)';
    }
}

export const inlineViewer = new InlineViewer();
