/**
 * VMO 360° Product Spin Viewer
 * Interactive drag/scroll-controlled product image rotation
 * 
 * Features:
 * - Mouse drag to rotate product
 * - Touch drag support for mobile
 * - Scroll-controlled playback (configurable)
 * - Inertia for smooth rotation
 * - Loop support
 * - Video mode (for Sora-generated 360° videos)
 * 
 * @package VMO_AI_Builder
 * @since 9.0.0
 */

(function() {
    'use strict';

    class VMO360SpinViewer {
        constructor(container, options = {}) {
            this.container = typeof container === 'string' 
                ? document.querySelector(container) 
                : container;
            
            if (!this.container) {
                console.error('VMO 360 Spin: Container not found');
                return;
            }

            // Default options
            this.options = Object.assign({
                frames: [],                    // Array of image URLs
                videoUrl: null,                // Alternative: use video instead of frames
                startFrame: 0,                 // Starting frame index
                loop: true,                    // Loop rotation
                autoplay: false,               // Auto-rotate on load
                autoplaySpeed: 50,             // ms per frame for autoplay
                autoplayDirection: 1,          // 1 = clockwise, -1 = counter-clockwise
                dragSensitivity: 5,            // Pixels of drag per frame
                reverseOnDrag: false,          // Reverse direction on drag
                inertia: 0.92,                 // Inertia decay (0-1, higher = more inertia)
                scrollControlled: false,       // Control playback via scroll
                scrollSensitivity: 2,          // Frames per scroll unit
                showControls: true,            // Show play/pause button
                showProgress: true,            // Show frame progress indicator
                loadingText: 'Loading 360° View...',
                cursor: 'grab',
                cursorActive: 'grabbing',
                responsive: true,              // Responsive sizing
            }, options);

            // State
            this.currentFrame = this.options.startFrame;
            this.frames = [];
            this.frameElements = [];
            this.isLoaded = false;
            this.isPlaying = false;
            this.isDragging = false;
            this.dragStartX = 0;
            this.velocity = 0;
            this.animationFrame = null;
            this.videoMode = !!this.options.videoUrl;

            // Initialize
            this.init();
        }

        init() {
            this.createDOM();
            
            if (this.videoMode) {
                this.loadVideo();
            } else {
                this.preloadFrames();
            }
            
            this.bindEvents();
        }

        createDOM() {
            this.container.classList.add('vmo-360-spin-viewer');
            this.container.innerHTML = `
                <div class="vmo-360-viewport">
                    <div class="vmo-360-loading">
                        <div class="vmo-360-loading-spinner"></div>
                        <span>${this.options.loadingText}</span>
                    </div>
                    <div class="vmo-360-frames"></div>
                    ${this.videoMode ? '<video class="vmo-360-video" muted playsinline></video>' : ''}
                </div>
                ${this.options.showControls ? `
                    <div class="vmo-360-controls">
                        <button class="vmo-360-btn vmo-360-btn-rotate" title="Drag to rotate">
                            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                <path d="M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/>
                            </svg>
                        </button>
                        ${this.options.autoplay ? `
                            <button class="vmo-360-btn vmo-360-btn-play" title="Play/Pause">
                                <svg class="play-icon" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
                                    <polygon points="5,3 19,12 5,21"/>
                                </svg>
                                <svg class="pause-icon" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" style="display:none">
                                    <rect x="6" y="4" width="4" height="16"/>
                                    <rect x="14" y="4" width="4" height="16"/>
                                </svg>
                            </button>
                        ` : ''}
                    </div>
                ` : ''}
                ${this.options.showProgress ? `
                    <div class="vmo-360-progress">
                        <div class="vmo-360-progress-bar"></div>
                    </div>
                ` : ''}
                <div class="vmo-360-hint">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
                        <path d="M14 2v6h6M9 15l2 2 4-4"/>
                    </svg>
                    <span>Drag to rotate</span>
                </div>
            `;

            this.viewport = this.container.querySelector('.vmo-360-viewport');
            this.framesContainer = this.container.querySelector('.vmo-360-frames');
            this.loadingEl = this.container.querySelector('.vmo-360-loading');
            this.progressBar = this.container.querySelector('.vmo-360-progress-bar');
            this.hintEl = this.container.querySelector('.vmo-360-hint');
            
            if (this.videoMode) {
                this.videoEl = this.container.querySelector('.vmo-360-video');
            }
            
            this.container.style.cursor = this.options.cursor;
        }

        async preloadFrames() {
            const frames = this.options.frames;
            if (!frames || frames.length === 0) {
                console.error('VMO 360 Spin: No frames provided');
                return;
            }

            let loaded = 0;
            const total = frames.length;

            const loadPromises = frames.map((src, index) => {
                return new Promise((resolve) => {
                    const img = new Image();
                    img.onload = () => {
                        loaded++;
                        this.updateLoadingProgress(loaded / total);
                        resolve();
                    };
                    img.onerror = () => {
                        console.warn(`VMO 360 Spin: Failed to load frame ${index}`);
                        loaded++;
                        resolve();
                    };
                    img.src = src;
                    img.className = 'vmo-360-frame';
                    img.style.display = index === this.currentFrame ? 'block' : 'none';
                    img.draggable = false;
                    
                    this.frameElements[index] = img;
                    this.framesContainer.appendChild(img);
                });
            });

            await Promise.all(loadPromises);
            this.onLoaded();
        }

        loadVideo() {
            if (!this.videoEl) return;
            
            this.videoEl.src = this.options.videoUrl;
            this.videoEl.load();
            
            this.videoEl.addEventListener('loadedmetadata', () => {
                this.totalFrames = Math.floor(this.videoEl.duration * 30); // Assume 30fps
                this.onLoaded();
            });
            
            this.videoEl.addEventListener('error', (e) => {
                console.error('VMO 360 Spin: Video load error', e);
            });
        }

        updateLoadingProgress(progress) {
            if (this.loadingEl) {
                const spinner = this.loadingEl.querySelector('.vmo-360-loading-spinner');
                if (spinner) {
                    spinner.style.background = `conic-gradient(var(--vmo-primary, #0066cc) ${progress * 360}deg, #eee 0deg)`;
                }
            }
        }

        onLoaded() {
            this.isLoaded = true;
            this.loadingEl.style.display = 'none';
            
            if (this.options.autoplay) {
                this.play();
            }
            
            // Show hint briefly
            if (this.hintEl) {
                this.hintEl.classList.add('visible');
                setTimeout(() => {
                    this.hintEl.classList.remove('visible');
                }, 3000);
            }
            
            this.updateProgress();
            
            // Dispatch loaded event
            this.container.dispatchEvent(new CustomEvent('vmo360:loaded', {
                detail: { frameCount: this.options.frames.length || this.totalFrames }
            }));
        }

        bindEvents() {
            // Mouse events
            this.viewport.addEventListener('mousedown', (e) => this.onDragStart(e));
            document.addEventListener('mousemove', (e) => this.onDragMove(e));
            document.addEventListener('mouseup', (e) => this.onDragEnd(e));
            
            // Touch events
            this.viewport.addEventListener('touchstart', (e) => this.onDragStart(e), { passive: false });
            document.addEventListener('touchmove', (e) => this.onDragMove(e), { passive: false });
            document.addEventListener('touchend', (e) => this.onDragEnd(e));
            
            // Scroll control
            if (this.options.scrollControlled) {
                this.bindScrollControl();
            }
            
            // Control buttons
            const playBtn = this.container.querySelector('.vmo-360-btn-play');
            if (playBtn) {
                playBtn.addEventListener('click', () => this.togglePlay());
            }
            
            // Prevent context menu on long press
            this.viewport.addEventListener('contextmenu', (e) => e.preventDefault());
        }

        bindScrollControl() {
            // Find the scroll container (could be the element itself or a parent)
            const scrollContainer = this.findScrollParent();
            
            if (!scrollContainer) return;
            
            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        this.enableScrollControl(scrollContainer);
                    } else {
                        this.disableScrollControl();
                    }
                });
            }, { threshold: 0.5 });
            
            observer.observe(this.container);
        }

        findScrollParent() {
            let parent = this.container.parentElement;
            while (parent) {
                const overflow = getComputedStyle(parent).overflow;
                if (overflow === 'auto' || overflow === 'scroll' || parent === document.body) {
                    return parent;
                }
                parent = parent.parentElement;
            }
            return window;
        }

        enableScrollControl(scrollContainer) {
            this.scrollHandler = (e) => {
                if (!this.isLoaded) return;
                
                const rect = this.container.getBoundingClientRect();
                const viewportHeight = window.innerHeight;
                
                // Calculate scroll progress within the element's visibility
                const elementTop = rect.top;
                const elementHeight = rect.height;
                const scrollProgress = 1 - ((elementTop + elementHeight) / (viewportHeight + elementHeight));
                
                if (scrollProgress >= 0 && scrollProgress <= 1) {
                    this.goToProgress(scrollProgress);
                }
            };
            
            (scrollContainer === window ? window : scrollContainer)
                .addEventListener('scroll', this.scrollHandler, { passive: true });
        }

        disableScrollControl() {
            if (this.scrollHandler) {
                window.removeEventListener('scroll', this.scrollHandler);
            }
        }

        onDragStart(e) {
            if (!this.isLoaded) return;
            
            e.preventDefault();
            this.isDragging = true;
            this.dragStartX = this.getEventX(e);
            this.dragStartFrame = this.currentFrame;
            this.velocity = 0;
            
            this.container.style.cursor = this.options.cursorActive;
            
            // Stop autoplay during drag
            if (this.isPlaying) {
                this.wasPlaying = true;
                this.pause();
            }
            
            // Hide hint on first drag
            if (this.hintEl) {
                this.hintEl.classList.remove('visible');
            }
        }

        onDragMove(e) {
            if (!this.isDragging) return;
            
            const x = this.getEventX(e);
            const deltaX = x - this.dragStartX;
            const frameChange = Math.floor(deltaX / this.options.dragSensitivity);
            
            if (this.options.reverseOnDrag) {
                this.velocity = -frameChange;
            } else {
                this.velocity = frameChange;
            }
            
            const newFrame = this.normalizeFrame(this.dragStartFrame + this.velocity);
            
            if (newFrame !== this.currentFrame) {
                this.goToFrame(newFrame);
            }
        }

        onDragEnd(e) {
            if (!this.isDragging) return;
            
            this.isDragging = false;
            this.container.style.cursor = this.options.cursor;
            
            // Apply inertia
            if (Math.abs(this.velocity) > 1 && this.options.inertia > 0) {
                this.applyInertia();
            }
            
            // Resume autoplay if it was playing
            if (this.wasPlaying) {
                this.wasPlaying = false;
                setTimeout(() => this.play(), 500);
            }
        }

        applyInertia() {
            if (Math.abs(this.velocity) < 0.5) {
                this.velocity = 0;
                return;
            }
            
            this.velocity *= this.options.inertia;
            const frameChange = Math.round(this.velocity / this.options.dragSensitivity);
            
            if (frameChange !== 0) {
                this.goToFrame(this.normalizeFrame(this.currentFrame + frameChange));
            }
            
            this.animationFrame = requestAnimationFrame(() => this.applyInertia());
        }

        getEventX(e) {
            if (e.touches && e.touches.length > 0) {
                return e.touches[0].clientX;
            }
            return e.clientX;
        }

        normalizeFrame(frame) {
            const total = this.videoMode ? this.totalFrames : this.options.frames.length;
            
            if (this.options.loop) {
                while (frame < 0) frame += total;
                return frame % total;
            }
            
            return Math.max(0, Math.min(total - 1, frame));
        }

        goToFrame(frame) {
            if (this.videoMode) {
                this.goToVideoFrame(frame);
            } else {
                this.goToImageFrame(frame);
            }
        }

        goToImageFrame(frame) {
            if (frame === this.currentFrame || !this.frameElements.length) return;
            
            // Hide current frame
            if (this.frameElements[this.currentFrame]) {
                this.frameElements[this.currentFrame].style.display = 'none';
            }
            
            // Show new frame
            this.currentFrame = frame;
            if (this.frameElements[this.currentFrame]) {
                this.frameElements[this.currentFrame].style.display = 'block';
            }
            
            this.updateProgress();
            
            // Dispatch frame change event
            this.container.dispatchEvent(new CustomEvent('vmo360:framechange', {
                detail: { frame: this.currentFrame, total: this.options.frames.length }
            }));
        }

        goToVideoFrame(frame) {
            if (!this.videoEl || !this.totalFrames) return;
            
            this.currentFrame = frame;
            const time = (frame / this.totalFrames) * this.videoEl.duration;
            this.videoEl.currentTime = time;
            
            this.updateProgress();
        }

        goToProgress(progress) {
            const total = this.videoMode ? this.totalFrames : this.options.frames.length;
            const frame = Math.floor(progress * (total - 1));
            this.goToFrame(frame);
        }

        updateProgress() {
            if (!this.progressBar) return;
            
            const total = this.videoMode ? this.totalFrames : this.options.frames.length;
            const progress = ((this.currentFrame + 1) / total) * 100;
            this.progressBar.style.width = `${progress}%`;
        }

        play() {
            if (this.isPlaying) return;
            
            this.isPlaying = true;
            this.updatePlayButton(true);
            
            if (this.videoMode) {
                this.videoEl.play();
            } else {
                this.autoplayLoop();
            }
        }

        pause() {
            this.isPlaying = false;
            this.updatePlayButton(false);
            
            if (this.videoMode) {
                this.videoEl.pause();
            }
            
            if (this.autoplayTimeout) {
                clearTimeout(this.autoplayTimeout);
            }
        }

        togglePlay() {
            if (this.isPlaying) {
                this.pause();
            } else {
                this.play();
            }
        }

        autoplayLoop() {
            if (!this.isPlaying) return;
            
            const nextFrame = this.normalizeFrame(
                this.currentFrame + this.options.autoplayDirection
            );
            this.goToFrame(nextFrame);
            
            this.autoplayTimeout = setTimeout(
                () => this.autoplayLoop(), 
                this.options.autoplaySpeed
            );
        }

        updatePlayButton(playing) {
            const playBtn = this.container.querySelector('.vmo-360-btn-play');
            if (!playBtn) return;
            
            const playIcon = playBtn.querySelector('.play-icon');
            const pauseIcon = playBtn.querySelector('.pause-icon');
            
            if (playIcon) playIcon.style.display = playing ? 'none' : 'block';
            if (pauseIcon) pauseIcon.style.display = playing ? 'block' : 'none';
        }

        destroy() {
            this.pause();
            this.disableScrollControl();
            
            if (this.animationFrame) {
                cancelAnimationFrame(this.animationFrame);
            }
            
            this.container.innerHTML = '';
            this.container.classList.remove('vmo-360-spin-viewer');
        }
    }

    // CSS Styles
    const styles = `
        .vmo-360-spin-viewer {
            position: relative;
            width: 100%;
            max-width: 800px;
            margin: 0 auto;
            user-select: none;
            -webkit-user-select: none;
            touch-action: pan-y;
        }
        
        .vmo-360-viewport {
            position: relative;
            width: 100%;
            padding-bottom: 100%; /* 1:1 aspect ratio by default */
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 12px;
            overflow: hidden;
        }
        
        .vmo-360-frames {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
        
        .vmo-360-frame {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: contain;
        }
        
        .vmo-360-video {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: contain;
        }
        
        .vmo-360-loading {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            color: #6c757d;
            font-size: 14px;
        }
        
        .vmo-360-loading-spinner {
            width: 60px;
            height: 60px;
            margin: 0 auto 12px;
            border-radius: 50%;
            background: conic-gradient(var(--vmo-primary, #0066cc) 0deg, #eee 0deg);
            position: relative;
        }
        
        .vmo-360-loading-spinner::before {
            content: '';
            position: absolute;
            top: 6px;
            left: 6px;
            right: 6px;
            bottom: 6px;
            background: white;
            border-radius: 50%;
        }
        
        .vmo-360-controls {
            position: absolute;
            bottom: 16px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            gap: 8px;
            background: rgba(255, 255, 255, 0.95);
            padding: 8px 12px;
            border-radius: 24px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.15);
        }
        
        .vmo-360-btn {
            width: 36px;
            height: 36px;
            border: none;
            background: transparent;
            cursor: pointer;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #333;
            transition: all 0.2s ease;
        }
        
        .vmo-360-btn:hover {
            background: rgba(0, 102, 204, 0.1);
            color: var(--vmo-primary, #0066cc);
        }
        
        .vmo-360-progress {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            height: 4px;
            background: rgba(0,0,0,0.1);
            border-radius: 0 0 12px 12px;
            overflow: hidden;
        }
        
        .vmo-360-progress-bar {
            height: 100%;
            background: var(--vmo-primary, #0066cc);
            width: 0;
            transition: width 0.1s ease;
        }
        
        .vmo-360-hint {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 12px 20px;
            border-radius: 24px;
            font-size: 14px;
            display: flex;
            align-items: center;
            gap: 8px;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s ease;
        }
        
        .vmo-360-hint.visible {
            opacity: 1;
        }
        
        .vmo-360-hint svg {
            flex-shrink: 0;
        }
        
        /* Responsive */
        @media (max-width: 768px) {
            .vmo-360-controls {
                bottom: 8px;
                padding: 6px 10px;
            }
            
            .vmo-360-btn {
                width: 32px;
                height: 32px;
            }
            
            .vmo-360-hint {
                font-size: 12px;
                padding: 10px 16px;
            }
        }
    `;

    // Inject styles
    if (!document.getElementById('vmo-360-spin-styles')) {
        const styleSheet = document.createElement('style');
        styleSheet.id = 'vmo-360-spin-styles';
        styleSheet.textContent = styles;
        document.head.appendChild(styleSheet);
    }

    // Export to global scope
    window.VMO360SpinViewer = VMO360SpinViewer;

    // Auto-initialize viewers with data attributes
    document.addEventListener('DOMContentLoaded', function() {
        document.querySelectorAll('[data-vmo-360-spin]').forEach(function(el) {
            const config = el.dataset.vmo360Spin;
            try {
                const options = config ? JSON.parse(config) : {};
                new VMO360SpinViewer(el, options);
            } catch (e) {
                console.error('VMO 360 Spin: Invalid config', e);
            }
        });
    });

})();
