import { BaseModule } from './base-module.js';
import { moduleRegistry } from './module-registry.js';
import { ModuleEvent } from './base-module.js';

class UIEffects extends BaseModule {
    constructor() {
        super('ui-effects');
        
        // No external dependencies
        this.dependencies = [];
        
        // Effects state
        this.activeEffects = new Map();
        this.ambientEffectsActive = false;
        
        // Effects configuration
        this.effectsConfig = {
            candleFlicker: {
                intensity: 0.5,
                speed: 0.8
            },
            textShadow: {
                enabled: true,
                color: 'rgba(0, 0, 0, 0.5)'
            },
            backgroundEffects: {
                enabled: true
            }
        };
        
        // Bind methods that use 'this' internally or are used as callbacks/event handlers
        this.initialize = this.initialize.bind(this); // Bind initialize as it calls dispatchEvent
        this.updateCandleEffect = this.updateCandleEffect.bind(this); // Used with requestAnimationFrame
        this.setupEffectElements = this.setupEffectElements.bind(this);
        this.createEffectsOverlay = this.createEffectsOverlay.bind(this);
        this.createCandleEffect = this.createCandleEffect.bind(this);
        this.createLightingElement = this.createLightingElement.bind(this);
        this.setupAmbientEffects = this.setupAmbientEffects.bind(this);
        this.setupCandleFlickerEffect = this.setupCandleFlickerEffect.bind(this);
        this.startAmbientEffects = this.startAmbientEffects.bind(this);
        this.stopAmbientEffects = this.stopAmbientEffects.bind(this);
        this.applyEffect = this.applyEffect.bind(this);
        this.applyShakeEffect = this.applyShakeEffect.bind(this);
        this.applyFlashEffect = this.applyFlashEffect.bind(this);
        this.applyTextEmphasis = this.applyTextEmphasis.bind(this);
        this.processCommand = this.processCommand.bind(this);
        
        // Store a bound version of dispatchEvent for use in methods
        this._dispatchModuleEvent = (name, detail) => {
            document.dispatchEvent(new CustomEvent(name, {
                detail: { moduleId: this.id, ...detail },
                bubbles: true
            }));
        };
        
        console.log('UIEffects: Constructor initialized');
    }

    async initialize() {
        this.reportProgress(0, 'Initializing UI Effects');
        
        try {
            this.reportProgress(30, 'Setting up effect elements');
            
            // Create or get effect elements
            this.setupEffectElements();
            
            this.reportProgress(60, 'Preparing ambient effects');
            
            // Set up ambient effect animations
            this.setupAmbientEffects();
            
            this.reportProgress(100, 'UI Effects ready');
            
            // Use the DOM event API directly instead of this.dispatchEvent
            this._dispatchModuleEvent('ui:effects:ready', {});
            
            return true;
        } catch (error) {
            console.error('Error initializing UI Effects:', error);
            this.changeState('ERROR');
            return false;
        }
    }
    
    setupEffectElements() {
        console.log('UIEffects: Setting up effect elements');
        // Create overlay for effects if it doesn't exist
        this.effectsOverlay = document.getElementById('effects-overlay') || this.createEffectsOverlay();
        
        // Create candle effect element
        this.candleEffectElement = document.getElementById('candle-effect') || this.createCandleEffect();
        
        // Ensure lighting element exists
        this.lightingElement = document.getElementById('lighting') || this.createLightingElement();
    }
    
    createEffectsOverlay() {
        const overlay = document.createElement('div');
        overlay.id = 'effects-overlay';
        overlay.className = 'effects-overlay';
        document.body.appendChild(overlay);
        return overlay;
    }
    
    createCandleEffect() {
        const candleEffect = document.createElement('div');
        candleEffect.id = 'candle-effect';
        candleEffect.className = 'candle-effect';
        if (this.effectsOverlay) {
            this.effectsOverlay.appendChild(candleEffect);
        } else {
            document.body.appendChild(candleEffect);
        }
        return candleEffect;
    }
    
    createLightingElement() {
        const lighting = document.createElement('div');
        lighting.id = 'lighting';
        document.body.appendChild(lighting);
        return lighting;
    }
    
    setupAmbientEffects() {
        // Initialize candle flicker effect
        if (this.candleEffectElement && this.effectsConfig.candleFlicker.enabled !== false) {
            this.setupCandleFlickerEffect();
        }
    }
    
    setupCandleFlickerEffect() {
        // Store the animation frame ID for later cancellation
        this.candleAnimationId = null;
    }
    
    updateCandleEffect() {
        if (!this.candleEffectElement || !this.ambientEffectsActive) return;
        
        const { intensity, speed } = this.effectsConfig.candleFlicker;
        
        // Create subtle random flickering effect
        const flickerAmount = Math.random() * intensity;
        const opacity = 0.2 + flickerAmount * 0.2;
        
        this.candleEffectElement.style.opacity = opacity;
        
        // Schedule next update
        this.candleAnimationId = requestAnimationFrame(this.updateCandleEffect);
    }
    
    // Public methods
    
    startAmbientEffects() {
        if (this.ambientEffectsActive) return;
        
        this.ambientEffectsActive = true;
        
        // Start candle flicker
        if (this.candleEffectElement) {
            this.updateCandleEffect();
        }
        
        // Apply lighting animation
        if (this.lightingElement) {
            this.lightingElement.style.animation = 'gradient-animation-shrink 2s infinite alternate';
        }
    }
    
    stopAmbientEffects() {
        this.ambientEffectsActive = false;
        
        // Stop candle flicker
        if (this.candleAnimationId) {
            cancelAnimationFrame(this.candleAnimationId);
            this.candleAnimationId = null;
        }
        
        // Stop lighting animation
        if (this.lightingElement) {
            this.lightingElement.style.animation = '';
        }
    }
    
    applyEffect(effectName, options = {}) {
        switch (effectName) {
            case 'shake':
                return this.applyShakeEffect(options);
            case 'flash':
                return this.applyFlashEffect(options);
            case 'emphasis':
                return this.applyTextEmphasis(options.text, options);
            default:
                console.warn(`Unknown effect: ${effectName}`);
                return null;
        }
    }
    
    applyShakeEffect(options = {}) {
        const target = options.target || document.getElementById('book');
        if (!target) return null;
        
        const intensity = options.intensity || 'medium';
        const duration = options.duration || 500;
        
        // Store original styles
        const originalTransition = target.style.transition;
        const originalTransform = target.style.transform;
        
        // Apply the shake animation
        target.style.transition = `transform ${duration}ms ease`;
        target.style.transform = 'translate(0, 0)';
        target.style.animation = `shake ${duration}ms 1`;
        
        // Return to normal after animation
        const effectId = setTimeout(() => {
            target.style.transition = originalTransition;
            target.style.transform = originalTransform;
            target.style.animation = '';
            this.activeEffects.delete(effectId);
        }, duration);
        
        this.activeEffects.set(effectId, { name: 'shake', target });
        return effectId;
    }
    
    applyFlashEffect(options = {}) {
        const color = options.color || 'white';
        const duration = options.duration || 300;
        
        // Create flash overlay if not exists
        let flashOverlay = document.getElementById('flash-overlay');
        if (!flashOverlay) {
            flashOverlay = document.createElement('div');
            flashOverlay.id = 'flash-overlay';
            flashOverlay.style.position = 'fixed';
            flashOverlay.style.top = '0';
            flashOverlay.style.left = '0';
            flashOverlay.style.width = '100%';
            flashOverlay.style.height = '100%';
            flashOverlay.style.pointerEvents = 'none';
            flashOverlay.style.zIndex = '9999';
            flashOverlay.style.opacity = '0';
            flashOverlay.style.transition = `opacity ${duration / 2}ms ease-in-out`;
            document.body.appendChild(flashOverlay);
        }
        
        // Set color and make visible
        flashOverlay.style.backgroundColor = color;
        
        // Start animation
        setTimeout(() => { flashOverlay.style.opacity = '0.8'; }, 10);
        
        const effectId = setTimeout(() => {
            flashOverlay.style.opacity = '0';
            this.activeEffects.delete(effectId);
            
            // Remove element after fade out
            setTimeout(() => {
                if (flashOverlay.parentNode) {
                    flashOverlay.parentNode.removeChild(flashOverlay);
                }
            }, duration / 2);
        }, duration / 2);
        
        this.activeEffects.set(effectId, { name: 'flash' });
        return effectId;
    }
    
    applyTextEmphasis(text, options = {}) {
        // Use existing display handler to show emphasized text
        const displayHandler = moduleRegistry.getModule('ui-display-handler');
        if (!displayHandler) return null;
        
        const style = {
            fontWeight: 'bold',
            color: options.color || '#990000',
            fontSize: options.size || '1.2em'
        };
        
        return displayHandler.displayText(text, { style, speak: true });
    }
    
    processCommand(command) {
        switch (command.action) {
            case 'apply':
                return this.applyEffect(command.effect, command.options);
            case 'cancel':
                const effectId = command.effectId;
                if (this.activeEffects.has(effectId)) {
                    clearTimeout(effectId);
                    this.activeEffects.delete(effectId);
                }
                break;
            case 'ambient':
                if (command.state === 'start') {
                    this.startAmbientEffects();
                } else if (command.state === 'stop') {
                    this.stopAmbientEffects();
                }
                break;
            default:
                console.warn(`Unknown effect command: ${command.action}`);
        }
    }
}

// Create the singleton instance
const uiEffects = new UIEffects();

// Register with the module registry
moduleRegistry.register(uiEffects);

// Export the module
export { uiEffects as UIEffects };

// Keep a reference in window for loader system
console.log('UIEffects: Registering with window');
window.UIEffects = uiEffects;
