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

class UIInputHandler extends BaseModule {
    constructor() {
        super('ui-input-handler');
        
        // Explicitly declare ui-display-handler as a dependency
        this.dependencies = ['ui-display-handler'];
        
        // Reference to display handler
        this.displayHandler = null;
        
        // Input elements
        this.inputArea = null;
        this.playerInput = null;
        this.cursor = null;
        this.commandHistoryElement = null;  // Changed: renamed to avoid conflict
        
        // Input state
        this.inputEnabled = true;
        this.historyIndex = -1;
        this.commandHistory = [];  // Now this is clearly the array of previous commands
        this.inputBuffer = '';
        
        // Add this method to properly dispatch custom events
        this._dispatchModuleEvent = (name, detail) => {
            document.dispatchEvent(new CustomEvent(name, {
                detail: { moduleId: this.id, ...detail },
                bubbles: true
            }));
        };
        
        // Bind method contexts
        this.setupInputElements = this.setupInputElements.bind(this);
        this.handlePlayerInput = this.handlePlayerInput.bind(this);
        this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
        this.positionCursor = this.positionCursor.bind(this);
        this.handleKeyboardInput = this.handleKeyboardInput.bind(this);
        
        console.log('UIInputHandler: Constructor initialized');
    }
    
    /**
     * Wait for dependencies before initializing
     * This ensures displayHandler is ready before we try to use it
     */
    async waitForDependencies() {
        try {
            // Explicitly wait for the display handler to be ready
            console.log('UIInputHandler: Waiting for display handler to be ready');
            
            // Get reference to the display handler
            this.displayHandler = moduleRegistry.getModule('ui-display-handler');
            
            if (!this.displayHandler) {
                console.error('UIInputHandler: Display handler dependency not found');
                return false;
            }
            
            // Wait for display handler to reach FINISHED state
            const displayHandlerReady = await moduleRegistry.waitForModule('ui-display-handler');
            if (!displayHandlerReady) {
                console.error('UIInputHandler: Display handler not ready after waiting');
                return false;
            }
            
            console.log('UIInputHandler: Display handler is ready');
            return true;
        } catch (error) {
            console.error('UIInputHandler: Error waiting for dependencies:', error);
            return false;
        }
    }
    
    /**
     * Initialize input handler
     */
    async initialize() {
        this.reportProgress(0, 'Initializing UI Input Handler');
        
        try {
            // Double-check display handler reference
            if (!this.displayHandler) {
                this.displayHandler = moduleRegistry.getModule('ui-display-handler');
                
                if (!this.displayHandler) {
                    console.error('UIInputHandler: Display handler still not available');
                    return false;
                }
            }
            
            this.reportProgress(30, 'Setting up keyboard listeners');
            
            // Set up keyboard event listeners
            document.addEventListener('keydown', (event) => {
                this.handleKeyboardInput(event);
            });
            
            this.reportProgress(60, 'Setting up input elements');
            
            // Set up input elements
            this.setupInputElements();
            
            this.reportProgress(100, 'UI Input Handler ready');
            return true;
        } catch (error) {
            console.error('Error initializing UI Input Handler:', error);
            return false;
        }
    }

    /**
     * Handle keyboard shortcuts and input globally
     * @param {KeyboardEvent} event - The keyboard event
     */
    handleKeyboardInput(event) {
        // Handle global keyboard shortcuts here
        // This is different from the input field's specific key handling
        
        // For example: Escape key to blur the input
        if (event.key === 'Escape') {
            if (document.activeElement === this.playerInput) {
                this.playerInput.blur();
            }
        }
    }

    setupInputElements() {
        console.log("UIInputHandler: Setting up input elements in document flow");
        
        // Find the left page - this is created by the display handler
        const pageLeft = document.getElementById('page_left');
        if (!pageLeft) {
            console.error('UIInputHandler: Left page not found, cannot create input elements');
            return;
        }
        
        // Only create choices container if it doesn't already exist
        let choicesContainer = document.getElementById('choices');
        if (!choicesContainer) {
            choicesContainer = document.createElement('div');
            choicesContainer.id = 'choices';
            choicesContainer.className = 'container';
            
            // Use natural document flow, not absolute positioning
            // Do NOT add a separator here, as it already exists in the CSS
            
            pageLeft.appendChild(choicesContainer);
        }
        
        // Create command history container if needed
        let commandHistory = document.getElementById('command_history');
        if (!commandHistory) {
            commandHistory = document.createElement('div');
            commandHistory.id = 'command_history';
            choicesContainer.appendChild(commandHistory);
            this.commandHistoryElement = commandHistory;  // Changed: store in renamed property
        } else {
            this.commandHistoryElement = commandHistory;  // Changed: store in renamed property
        }
        
        // Create input container if needed
        let commandInput = document.getElementById('command_input');
        if (!commandInput) {
            commandInput = document.createElement('div');
            commandInput.id = 'command_input';
            choicesContainer.appendChild(commandInput);
        }
        
        // Create input wrapper if needed
        let inputWrapper = commandInput.querySelector('.input-wrapper');
        if (!inputWrapper) {
            inputWrapper = document.createElement('div');
            inputWrapper.className = 'input-wrapper';
            commandInput.appendChild(inputWrapper);
        }
        
        // Create the textarea if needed
        let playerInput = document.getElementById('player_input');
        if (!playerInput) {
            playerInput = document.createElement('textarea');
            playerInput.id = 'player_input';
            playerInput.rows = 1;
            playerInput.placeholder = 'What will you do?';
            playerInput.setAttribute('autocomplete', 'off');
            playerInput.setAttribute('spellcheck', 'true');
            
            // Fix horizontal scrolling by ensuring the textbox wraps text
            playerInput.style.overflowX = 'hidden';  
            playerInput.style.wordWrap = 'break-word';
            playerInput.style.whiteSpace = 'pre-wrap';
            
            inputWrapper.appendChild(playerInput);
            this.playerInput = playerInput;
        }
        
        // Create the cursor if needed
        let cursor = document.getElementById('cursor');
        if (!cursor) {
            cursor = document.createElement('span');
            cursor.id = 'cursor';
            inputWrapper.appendChild(cursor);
            this.cursor = cursor;
        }
        
        // Set up input event handlers
        if (playerInput) {
            playerInput.addEventListener('input', this.handlePlayerInput);
            playerInput.addEventListener('keydown', this.handleInputKeyDown);
            
            // Auto-resize input field
            playerInput.addEventListener('input', () => {
                playerInput.style.height = 'auto';
                playerInput.style.height = playerInput.scrollHeight + 'px';
            });
        }
        
        // Position the cursor
        if (playerInput && cursor) {
            this.positionCursor(playerInput, cursor);
            
            // Focus the input to let user start typing immediately
            setTimeout(() => {
                playerInput.focus();
            }, 100);
        }
        
        console.log('UIInputHandler: Input elements setup complete');
    }

    /**
     * Handle player input changes
     * @param {Event} e - Input event
     */
    handlePlayerInput(e) {
        if (!this.playerInput) return;
        
        // Auto-resize the input field based on content
        this.playerInput.style.height = 'auto';
        this.playerInput.style.height = `${this.playerInput.scrollHeight}px`;
        
        // Update the cursor position with the current input text
        if (this.cursor) {
            this.positionCursor(this.playerInput, this.cursor);
        }
        
        // Dispatch event using the properly defined method
        this._dispatchModuleEvent('ui:input:change', { 
            text: this.playerInput.value
        });
    }

    /**
     * Handle key down events in the input field
     * @param {KeyboardEvent} e - Keyboard event
     */
    handleInputKeyDown(e) {
        if (!this.playerInput) return;
        
        // Check for Enter key
        if (e.key === 'Enter') {
            if (!e.shiftKey) {
                // Prevent default (new line) if not holding shift
                e.preventDefault();
                
                // Submit command
                this.submitCommand();
            }
        }
    }
    
    /**
     * Submit the current input as a command
     */
    submitCommand() {
        if (!this.playerInput || !this.playerInput.value.trim()) return;
        
        const command = this.playerInput.value.trim();
        console.log(`UIInputHandler: Submitting command: "${command}"`);
        
        // Add command to history
        this.addToHistory(command);
        
        // Dispatch command event
        this._dispatchModuleEvent('ui:command', {
            type: 'input',
            text: command
        });
        
        // Clear input field
        this.playerInput.value = '';
        this.playerInput.style.height = 'auto';
        
        // Update cursor position
        if (this.cursor) {
            this.positionCursor(this.playerInput, this.cursor);
        }
        
        // Focus input field
        this.playerInput.focus();
    }
    
    /**
     * Add command to history
     * @param {string} command - Command to add to history
     */
    addToHistory(command) {
        // Add to history array
        this.commandHistory.push(command);
        
        // Limit history size
        if (this.commandHistory.length > 50) {
            this.commandHistory.shift();
        }
        
        // Reset history index
        this.historyIndex = -1;
        
        // Update visual history if element exists
        if (this.commandHistoryElement && this.commandHistoryElement.appendChild) {
            const historyItem = document.createElement('div');
            historyItem.className = 'history-item';
            historyItem.textContent = `> ${command}`;
            this.commandHistoryElement.appendChild(historyItem);
            
            // Limit visible history items
            while (this.commandHistoryElement.childElementCount > 10) {
                this.commandHistoryElement.removeChild(this.commandHistoryElement.firstChild);
            }
            
            // Scroll to bottom
            this.commandHistoryElement.scrollTop = this.commandHistoryElement.scrollHeight;
        }
    }

    /**
     * Resets the cursor position to the start.
     */
    resetCursorPosition() {
        if (this.cursor) {
            this.cursor.style.left = '0px';
            // Adjust top based on computed style padding or a default
            const computedStyle = window.getComputedStyle(this.playerInput);
            const paddingTop = parseFloat(computedStyle.paddingTop) || 6;
            this.cursor.style.top = `${paddingTop}px`;
        }
    }


    /**
     * Position cursor based on input text position
     * @param {HTMLTextAreaElement} inputElement - The input element
     * @param {HTMLElement} cursorElement - The visual cursor element
     */
    positionCursor(inputElement, cursorElement) {
        if (!inputElement || !cursorElement) return;
    
        this.cursor = cursorElement;
        this.playerInput = inputElement;
        const updatePosition = () => {
            try {
                const input = this.playerInput;
                const cursor = this.cursor;
                const caretPosition = input.selectionStart || 0;
                const inputText = input.value;
            
                // If no text, position cursor at the beginning based on padding
                if (inputText.length === 0 && caretPosition === 0) {
                    this.resetCursorPosition();
                    return;
                }
            
                // Create a temporary measurement div
                const div = document.createElement('div');
                const style = getComputedStyle(input);
            
                // Apply relevant styles from the textarea to the div
                div.style.position = 'absolute';
                div.style.top = '-9999px';
                div.style.left = '-9999px';
                div.style.width = style.width;
                div.style.height = 'auto';
                div.style.padding = style.padding;
                div.style.border = style.border;
                div.style.fontFamily = style.fontFamily;
                div.style.fontSize = style.fontSize;
                div.style.fontWeight = style.fontWeight;
                div.style.lineHeight = style.lineHeight;
                div.style.whiteSpace = 'pre-wrap';
                div.style.wordWrap = 'break-word';
                div.style.boxSizing = style.boxSizing;
            
                // Create spans for text before and after the caret, and a marker span
                const preCaretText = document.createTextNode(inputText.substring(0, caretPosition));
                const caretMarker = document.createElement('span');
                caretMarker.innerHTML = '&nbsp;'; // Use non-breaking space for measurement
                const postCaretText = document.createTextNode(inputText.substring(caretPosition));
            
                // Append spans to the div
                div.appendChild(preCaretText);
                div.appendChild(caretMarker);
                div.appendChild(postCaretText);
            
                // Append div to body for measurement
                document.body.appendChild(div);
            
                // Get position relative to the div's content box
                const markerRect = caretMarker.getBoundingClientRect();
                const divRect = div.getBoundingClientRect();
            
                // Calculate position relative to the input's top-left, considering scroll
                const cursorLeft = markerRect.left - divRect.left;
                const cursorTop = markerRect.top - divRect.top - input.scrollTop;
            
                // Set cursor position
                cursor.style.left = `${cursorLeft}px`;
                cursor.style.top = `${cursorTop}px`;
            
                // Clean up the temporary div
                document.body.removeChild(div);            } catch (error) {
                console.error('Error positioning cursor:', error);
            }
        };
        
        // Update on various events
        inputElement.addEventListener('input', updatePosition);
        inputElement.addEventListener('click', updatePosition);
        inputElement.addEventListener('keyup', updatePosition);
        inputElement.addEventListener('focus', updatePosition);
        
        // Initial position update
        updatePosition();
    }
}

// Create the singleton instance
const uiInputHandler = new UIInputHandler();

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

// Export the module
export { uiInputHandler as UIInputHandler };

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