// SPORE UI Framework - Component-based architecture with pub/sub system

// Lightweight logger with level gating
const logger = {
    debug: (...args) => { try { if (window && window.DEBUG) { console.debug(...args); } } catch (_) { /* no-op */ } },
    info: (...args) => console.info(...args),
    warn: (...args) => console.warn(...args),
    error: (...args) => console.error(...args),
};
if (typeof window !== 'undefined') {
    window.logger = window.logger || logger;
}

// Event Bus for pub/sub communication
class EventBus {
    constructor() {
        this.events = new Map();
    }

    // Subscribe to an event
    subscribe(event, callback) {
        if (!this.events.has(event)) {
            this.events.set(event, []);
        }
        this.events.get(event).push(callback);
        
        // Return unsubscribe function
        return () => {
            const callbacks = this.events.get(event);
            if (callbacks) {
                const index = callbacks.indexOf(callback);
                if (index > -1) {
                    callbacks.splice(index, 1);
                }
            }
        };
    }

    // Publish an event
    publish(event, data) {
        if (this.events.has(event)) {
            this.events.get(event).forEach(callback => {
                try {
                    callback(data);
                } catch (error) {
                    console.error(`Error in event callback for ${event}:`, error);
                }
            });
        }
    }

    // Unsubscribe from an event
    unsubscribe(event, callback) {
        if (this.events.has(event)) {
            const callbacks = this.events.get(event);
            const index = callbacks.indexOf(callback);
            if (index > -1) {
                callbacks.splice(index, 1);
            }
        }
    }

    // Clear all events
    clear() {
        this.events.clear();
    }
}

// Base ViewModel class with enhanced state management
class ViewModel {
    constructor() {
        this._data = {};
        this._listeners = new Map();
        this._eventBus = null;
        this._uiState = new Map(); // Store UI state like active tabs, expanded cards, etc.
        this._previousData = {}; // Store previous data for change detection
    }

    // Set the event bus for this view model
    setEventBus(eventBus) {
        this._eventBus = eventBus;
    }

    // Get data property
    get(property) {
        return this._data[property];
    }

    // Set data property and notify listeners
    set(property, value) {
        logger.debug(`ViewModel: Setting property '${property}' to:`, value);
        
        // Check if the value has actually changed
        const hasChanged = this._data[property] !== value;
        
        if (hasChanged) {
            // Store previous value for change detection
            this._previousData[property] = this._data[property];
            
            // Update the data
            this._data[property] = value;
            
            logger.debug(`ViewModel: Property '${property}' changed, notifying listeners...`);
            this._notifyListeners(property, value, this._previousData[property]);
        } else {
            logger.debug(`ViewModel: Property '${property}' unchanged, skipping notification`);
        }
    }

    // Set multiple properties at once with change detection
    setMultiple(properties) {
        const changedProperties = {};
        
        // Determine changes and update previousData snapshot per key
        Object.keys(properties).forEach(key => {
            const newValue = properties[key];
            const oldValue = this._data[key];
            if (oldValue !== newValue) {
                this._previousData[key] = oldValue;
                changedProperties[key] = newValue;
            }
        });
        
        // Apply all properties
        Object.keys(properties).forEach(key => {
            this._data[key] = properties[key];
        });
        
        // Notify listeners only for changed properties with accurate previous values
        Object.keys(changedProperties).forEach(key => {
            this._notifyListeners(key, this._data[key], this._previousData[key]);
        });
        
        if (Object.keys(changedProperties).length > 0) {
            logger.debug(`ViewModel: Updated ${Object.keys(changedProperties).length} changed properties:`, Object.keys(changedProperties));
        }
    }

    // Subscribe to property changes
    subscribe(property, callback) {
        if (!this._listeners.has(property)) {
            this._listeners.set(property, []);
        }
        this._listeners.get(property).push(callback);
        
        // Return unsubscribe function
        return () => {
            const callbacks = this._listeners.get(property);
            if (callbacks) {
                const index = callbacks.indexOf(callback);
                if (index > -1) {
                    callbacks.splice(index, 1);
                }
            }
        };
    }

    // Notify listeners of property changes
    _notifyListeners(property, value, previousValue) {
        logger.debug(`ViewModel: _notifyListeners called for property '${property}'`);
        if (this._listeners.has(property)) {
            const callbacks = this._listeners.get(property);
            logger.debug(`ViewModel: Found ${callbacks.length} listeners for property '${property}'`);
            callbacks.forEach((callback, index) => {
                try {
                    logger.debug(`ViewModel: Calling listener ${index} for property '${property}'`);
                    callback(value, previousValue);
                } catch (error) {
                    console.error(`Error in property listener for ${property}:`, error);
                }
            });
        } else {
            logger.debug(`ViewModel: No listeners found for property '${property}'`);
        }
    }

    // Publish event to event bus
    publish(event, data) {
        if (this._eventBus) {
            this._eventBus.publish(event, data);
        }
    }

    // Get all data
    getAll() {
        return { ...this._data };
    }

    // Clear all data
    clear() {
        this._data = {};
        this._listeners.clear();
    }

    // UI State Management Methods
    setUIState(key, value) {
        this._uiState.set(key, value);
    }

    getUIState(key) {
        return this._uiState.get(key);
    }

    getAllUIState() {
        return new Map(this._uiState);
    }

    clearUIState(key) {
        if (key) {
            this._uiState.delete(key);
        } else {
            this._uiState.clear();
        }
    }

    // Check if a property has changed
    hasChanged(property) {
        return this._data[property] !== this._previousData[property];
    }

    // Get previous value of a property
    getPrevious(property) {
        return this._previousData[property];
    }

    // Batch update with change detection
    batchUpdate(updates, options = {}) {
        const { notifyChanges = true } = options;
        
        // Track which keys actually change and what the previous values were
        const changedKeys = [];
        Object.keys(updates).forEach(key => {
            const newValue = updates[key];
            const oldValue = this._data[key];
            if (oldValue !== newValue) {
                this._previousData[key] = oldValue;
                this._data[key] = newValue;
                changedKeys.push(key);
            } else {
                // Still apply to ensure consistency if needed
                this._data[key] = newValue;
            }
        });
        
        // Notify listeners for changed keys
        if (notifyChanges) {
            changedKeys.forEach(key => {
                this._notifyListeners(key, this._data[key], this._previousData[key]);
            });
        }
    }
}

// Base Component class
class Component {
    constructor(container, viewModel, eventBus) {
        this.container = container;
        this.viewModel = viewModel;
        this.eventBus = eventBus;
        this.isMounted = false;
        this.unsubscribers = [];
        this.uiState = new Map(); // Local UI state for this component
        
        // Set event bus on view model
        if (this.viewModel) {
            this.viewModel.setEventBus(eventBus);
        }
        
        // Bind methods
        this.render = this.render.bind(this);
        this.mount = this.mount.bind(this);
        this.unmount = this.unmount.bind(this);
        this.updatePartial = this.updatePartial.bind(this);
    }

    // Mount the component
    mount() {
        if (this.isMounted) return;
        
        logger.debug(`${this.constructor.name}: Starting mount...`);
        this.isMounted = true;
        this.setupEventListeners();
        this.setupViewModelListeners();
        this.render();
        
        logger.debug(`${this.constructor.name}: Mounted successfully`);
    }

    // Unmount the component
    unmount() {
        if (!this.isMounted) return;
        
        this.isMounted = false;
        this.cleanupEventListeners();
        this.cleanupViewModelListeners();
        
        logger.debug(`${this.constructor.name} unmounted`);
    }

    // Pause the component (keep alive but pause activity)
    pause() {
        if (!this.isMounted) return;
        
        logger.debug(`${this.constructor.name}: Pausing component`);
        
        // Pause any active timers or animations
        if (this.updateInterval) {
            clearInterval(this.updateInterval);
            this.updateInterval = null;
        }
        
        // Pause any ongoing operations
        this.isPaused = true;
        
        // Override in subclasses to pause specific functionality
        this.onPause();
    }

    // Resume the component
    resume() {
        if (!this.isMounted || !this.isPaused) return;
        
        logger.debug(`${this.constructor.name}: Resuming component`);
        
        this.isPaused = false;
        
        // Restart any necessary timers or operations
        this.onResume();
        
        // Re-render if needed
        if (this.shouldRenderOnResume()) {
            this.render();
        }
    }

    // Override in subclasses to handle pause-specific logic
    onPause() {
        // Default implementation does nothing
    }

    // Override in subclasses to handle resume-specific logic
    onResume() {
        // Default implementation does nothing
    }

    // Override in subclasses to determine if re-render is needed on resume
    shouldRenderOnResume() {
        // Default: don't re-render on resume
        return false;
    }

    // Setup event listeners (override in subclasses)
    setupEventListeners() {
        // Override in subclasses
    }

    // Setup view model listeners (override in subclasses)
    setupViewModelListeners() {
        // Override in subclasses
    }

    // Cleanup event listeners (override in subclasses)
    cleanupEventListeners() {
        // Override in subclasses
    }

    // Cleanup view model listeners (override in subclasses)
    cleanupViewModelListeners() {
        // Override in subclasses
    }

    // Render the component (override in subclasses)
    render() {
        // Override in subclasses
    }

    // Partial update method for efficient data updates
    updatePartial(property, newValue, previousValue) {
        // Override in subclasses to implement partial updates
        logger.debug(`${this.constructor.name}: Partial update for '${property}':`, { newValue, previousValue });
    }

    // UI State Management Methods
    setUIState(key, value) {
        this.uiState.set(key, value);
        // Also store in view model for persistence across refreshes
        if (this.viewModel) {
            this.viewModel.setUIState(key, value);
        }
    }

    getUIState(key) {
        // First try local state, then view model state
        return this.uiState.get(key) || (this.viewModel ? this.viewModel.getUIState(key) : null);
    }

    getAllUIState() {
        const localState = new Map(this.uiState);
        const viewModelState = this.viewModel ? this.viewModel.getAllUIState() : new Map();
        
        // Merge states, with local state taking precedence
        const mergedState = new Map(viewModelState);
        localState.forEach((value, key) => mergedState.set(key, value));
        
        return mergedState;
    }

    clearUIState(key) {
        if (key) {
            this.uiState.delete(key);
            if (this.viewModel) {
                this.viewModel.clearUIState(key);
            }
        } else {
            this.uiState.clear();
            if (this.viewModel) {
                this.viewModel.clearUIState();
            }
        }
    }

    // Restore UI state from view model
    restoreUIState() {
        if (this.viewModel) {
            const viewModelState = this.viewModel.getAllUIState();
            viewModelState.forEach((value, key) => {
                this.uiState.set(key, value);
            });
        }
    }

    // Helper method to add event listener and track for cleanup
    addEventListener(element, event, handler) {
        element.addEventListener(event, handler);
        this.unsubscribers.push(() => {
            element.removeEventListener(event, handler);
        });
    }

    // Helper method to subscribe to event bus and track for cleanup
    subscribeToEvent(event, handler) {
        const unsubscribe = this.eventBus.subscribe(event, handler);
        this.unsubscribers.push(unsubscribe);
    }

    // Helper method to subscribe to view model property and track for cleanup
    subscribeToProperty(property, handler) {
        if (this.viewModel) {
            const unsubscribe = this.viewModel.subscribe(property, (newValue, previousValue) => {
                // Call handler with both new and previous values for change detection
                handler(newValue, previousValue);
            });
            this.unsubscribers.push(unsubscribe);
        }
    }

    // Helper method to find element within component container
    findElement(selector) {
        return this.container.querySelector(selector);
    }

    // Helper method to find all elements within component container
    findAllElements(selector) {
        return this.container.querySelectorAll(selector);
    }

    // Helper method to set innerHTML safely
    setHTML(selector, html) {
        logger.debug(`${this.constructor.name}: setHTML called with selector '${selector}', html length: ${html.length}`);
        
        let element;
        if (selector === '') {
            // Empty selector means set HTML on the component's container itself
            element = this.container;
            logger.debug(`${this.constructor.name}: Using component container for empty selector`);
        } else {
            // Find element within the component's container
            element = this.findElement(selector);
        }
        
        if (element) {
            logger.debug(`${this.constructor.name}: Element found, setting innerHTML`);
            element.innerHTML = html;
            logger.debug(`${this.constructor.name}: innerHTML set successfully`);
        } else {
            console.error(`${this.constructor.name}: Element not found for selector '${selector}'`);
        }
    }

    // Helper method to set text content safely
    setText(selector, text) {
        const element = this.findElement(selector);
        if (element) {
            element.textContent = text;
        }
    }

    // Helper method to add/remove CSS classes
    setClass(selector, className, add = true) {
        const element = this.findElement(selector);
        if (element) {
            if (add) {
                element.classList.add(className);
            } else {
                element.classList.remove(className);
            }
        }
    }

    // Helper method to set CSS styles
    setStyle(selector, property, value) {
        const element = this.findElement(selector);
        if (element) {
            element.style[property] = value;
        }
    }

    // Helper method to show/hide elements
    setVisible(selector, visible) {
        const element = this.findElement(selector);
        if (element) {
            element.style.display = visible ? '' : 'none';
        }
    }

    // Helper method to enable/disable elements
    setEnabled(selector, enabled) {
        const element = this.findElement(selector);
        if (element) {
            element.disabled = !enabled;
        }
    }

    // Reusable render helpers
    renderLoading(customHtml) {
        const html = customHtml || `
            <div class="loading">
                <div>Loading...</div>
            </div>
        `;
        this.setHTML('', html);
    }

    renderError(message) {
        const safe = this.escapeHtml(String(message || 'An error occurred'));
        const html = `
            <div class="error">
                <strong>Error:</strong><br>
                ${safe}
            </div>
        `;
        this.setHTML('', html);
    }

    renderEmpty(customHtml) {
        const html = customHtml || `
            <div class="empty-state">
                <div>No data</div>
            </div>
        `;
        this.setHTML('', html);
    }

    // Basic HTML escaping for dynamic values
    escapeHtml(str) {
        return String(str)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    // Tab helpers
    setupTabs(container = this.container, options = {}) {
        const { onChange } = options;
        const tabButtons = container.querySelectorAll('.tab-button');
        const tabContents = container.querySelectorAll('.tab-content');
        tabButtons.forEach(button => {
            this.addEventListener(button, 'click', (e) => {
                e.stopPropagation();
                const targetTab = button.dataset.tab;
                this.setActiveTab(targetTab, container);
                if (typeof onChange === 'function') {
                    try { onChange(targetTab); } catch (_) {}
                }
            });
        });
        tabContents.forEach(content => {
            this.addEventListener(content, 'click', (e) => {
                e.stopPropagation();
            });
        });
    }

    setActiveTab(tabName, container = this.container) {
        const tabButtons = container.querySelectorAll('.tab-button');
        const tabContents = container.querySelectorAll('.tab-content');
        tabButtons.forEach(btn => btn.classList.remove('active'));
        tabContents.forEach(content => content.classList.remove('active'));
        const activeButton = container.querySelector(`[data-tab="${tabName}"]`);
        const activeContent = container.querySelector(`#${tabName}-tab`);
        if (activeButton) activeButton.classList.add('active');
        if (activeContent) activeContent.classList.add('active');
        logger.debug(`${this.constructor.name}: Active tab set to '${tabName}'`);
    }
}

// Application class to manage components and routing
class App {
    constructor() {
        this.eventBus = new EventBus();
        this.components = new Map();
        this.currentView = null;
        this.routes = new Map();
        this.navigationInProgress = false;
        this.navigationQueue = [];
        this.lastNavigationTime = 0;
        this.navigationCooldown = (window.CONSTANTS && window.CONSTANTS.TIMING.NAV_COOLDOWN_MS) || 300; // cooldown between navigations
        
        // Component cache to keep components alive
        this.componentCache = new Map();
        this.cachedViews = new Set();
    }

    // Register a route
    registerRoute(name, componentClass, containerId, viewModel = null) {
        this.routes.set(name, { componentClass, containerId, viewModel });
        
        // Defer instantiation until navigation to reduce startup work
        // this.preInitializeComponent(name, componentClass, containerId, viewModel);
    }

    // Pre-initialize component in cache
    preInitializeComponent(name, componentClass, containerId, viewModel) {
        const container = document.getElementById(containerId);
        if (!container) return;
        
        // Create component instance but don't mount it yet
        const component = new componentClass(container, viewModel, this.eventBus);
        component.routeName = name;
        component.isCached = true;
        
        // Store in cache
        this.componentCache.set(name, component);
        logger.debug(`App: Pre-initialized component for route '${name}'`);
    }

    // Navigate to a route
    navigateTo(routeName, updateUrl = true) {
        // Check cooldown period
        const now = Date.now();
        if (now - this.lastNavigationTime < this.navigationCooldown) {
            logger.debug(`App: Navigation cooldown active, skipping route '${routeName}'`);
            return;
        }
        
        // If navigation is already in progress, queue this request
        if (this.navigationInProgress) {
            logger.debug(`App: Navigation in progress, queuing route '${routeName}'`);
            if (!this.navigationQueue.includes(routeName)) {
                this.navigationQueue.push(routeName);
            }
            return;
        }

        // If trying to navigate to the same route, do nothing
        if (this.currentView && this.currentView.routeName === routeName) {
            logger.debug(`App: Already on route '${routeName}', skipping navigation`);
            return;
        }

        // Update URL if requested
        if (updateUrl) {
            this.updateURL(routeName);
        }

        this.lastNavigationTime = now;
        this.performNavigation(routeName);
    }

    // Update browser URL
    updateURL(routeName) {
        const url = `/${routeName}`;
        if (window.location.pathname !== url) {
            window.history.pushState({ route: routeName }, '', url);
            logger.debug(`App: Updated URL to ${url}`);
        }
    }

    // Get route from current URL
    getRouteFromURL() {
        const path = window.location.pathname;
        // Remove leading slash and use as route name
        const routeName = path.substring(1) || 'cluster'; // default to cluster
        return routeName;
    }

    // Handle browser back/forward
    handlePopState(event) {
        if (event.state && event.state.route) {
            logger.debug(`App: Handling popstate for route '${event.state.route}'`);
            this.navigateTo(event.state.route, false); // Don't update URL again
        } else {
            // Fallback: parse URL
            const routeName = this.getRouteFromURL();
            logger.debug(`App: Handling popstate, navigating to '${routeName}'`);
            this.navigateTo(routeName, false);
        }
    }

    // Perform the actual navigation
    async performNavigation(routeName) {
        this.navigationInProgress = true;
        
        try {
            logger.debug(`App: Navigating to route '${routeName}'`);
            const route = this.routes.get(routeName);
            if (!route) {
                console.error(`Route '${routeName}' not found`);
                return;
            }

            logger.debug(`App: Route found, component: ${route.componentClass.name}, container: ${route.containerId}`);

            // Get or create component from cache
            let component = this.componentCache.get(routeName);
            if (!component) {
                logger.debug(`App: Component not in cache, creating new instance for '${routeName}'`);
                const container = document.getElementById(route.containerId);
                if (!container) {
                    console.error(`Container '${route.containerId}' not found`);
                    return;
                }
                
                component = new route.componentClass(container, route.viewModel, this.eventBus);
                component.routeName = routeName;
                component.isCached = true;
                this.componentCache.set(routeName, component);
            }

            // Hide current view smoothly
            if (this.currentView) {
                logger.debug('App: Hiding current view');
                await this.hideCurrentView();
            }

            // Show new view
            logger.debug(`App: Showing new view '${routeName}'`);
            await this.showView(routeName, component);

            // Update navigation state
            this.updateNavigation(routeName);
            
            // Set as current view
            this.currentView = component;
            
            // Mark view as cached for future use
            this.cachedViews.add(routeName);
            
            logger.debug(`App: Navigation to '${routeName}' completed`);

        } catch (error) {
            console.error('App: Navigation failed:', error);
        } finally {
            this.navigationInProgress = false;
            
            // Process any queued navigation requests
            if (this.navigationQueue.length > 0) {
                const nextRoute = this.navigationQueue.shift();
                logger.debug(`App: Processing queued navigation to '${nextRoute}'`);
                setTimeout(() => this.navigateTo(nextRoute), 100);
            }
        }
    }

    // Hide current view smoothly
    async hideCurrentView() {
        if (!this.currentView) return;
        
        // If component is mounted, pause it instead of unmounting
        if (this.currentView.isMounted) {
            logger.debug('App: Pausing current view instead of unmounting');
            this.currentView.pause();
        }
        
        // Fade out the container
        if (this.currentView.container) {
            this.currentView.container.style.opacity = '0';
            this.currentView.container.style.transition = `opacity ${(window.CONSTANTS && window.CONSTANTS.TIMING.VIEW_FADE_OUT_MS) || 150}ms ease-out`;
        }
        
        // Wait for fade out to complete
        await new Promise(resolve => setTimeout(resolve, (window.CONSTANTS && window.CONSTANTS.TIMING.VIEW_FADE_OUT_MS) || 150));
    }

    // Show view smoothly
    async showView(routeName, component) {
        const container = component.container;
        
        // Ensure component is mounted (but not necessarily active); lazy-create now if needed
        if (!component) {
            const route = this.routes.get(routeName);
            const container = document.getElementById(route.containerId);
            component = new route.componentClass(container, route.viewModel, this.eventBus);
            component.routeName = routeName;
            component.isCached = true;
            this.componentCache.set(routeName, component);
        }
        if (!component.isMounted) {
            logger.debug(`App: Mounting component for '${routeName}'`);
            component.mount();
        } else {
            logger.debug(`App: Resuming component for '${routeName}'`);
            component.resume();
        }
        
        // Fade in the container
        container.style.opacity = '0';
        container.style.transition = `opacity ${(window.CONSTANTS && window.CONSTANTS.TIMING.VIEW_FADE_IN_MS) || 200}ms ease-in`;
        
        // Small delay to ensure smooth transition
        await new Promise(resolve => setTimeout(resolve, (window.CONSTANTS && window.CONSTANTS.TIMING.VIEW_FADE_DELAY_MS) || 50));
        
        // Fade in
        container.style.opacity = '1';
    }

    // Update navigation state
    updateNavigation(activeRoute) {
        // Remove active class from all nav tabs
        document.querySelectorAll((window.CONSTANTS && window.CONSTANTS.SELECTORS.NAV_TAB) || '.nav-tab').forEach(tab => {
            tab.classList.remove('active');
        });

        // Add active class to current route tab
        const activeTab = document.querySelector(`[data-view="${activeRoute}"]`);
        if (activeTab) {
            activeTab.classList.add('active');
        }

        // Hide all view contents with smooth transition
        document.querySelectorAll((window.CONSTANTS && window.CONSTANTS.SELECTORS.VIEW_CONTENT) || '.view-content').forEach(view => {
            view.classList.remove('active');
            view.style.opacity = '0';
            view.style.transition = 'opacity 0.15s ease-out';
        });

        // Show current view content with smooth transition
        const activeView = document.getElementById(`${activeRoute}-view`);
        if (activeView) {
            activeView.classList.add('active');
            // Small delay to ensure smooth transition
            setTimeout(() => {
                activeView.style.opacity = '1';
                activeView.style.transition = 'opacity 0.2s ease-in';
            }, 50);
        }
    }

    // Register a component
    registerComponent(name, component) {
        this.components.set(name, component);
    }

    // Get a component by name
    getComponent(name) {
        return this.components.get(name);
    }

    // Get the event bus
    getEventBus() {
        return this.eventBus;
    }

    // Initialize the application
    init() {
        logger.debug('SPORE UI Framework initialized');
        
        // Note: Navigation is now handled by the app initialization
        // to ensure routes are registered before navigation
    }

    // Setup navigation
    setupNavigation() {
        // Intercept navigation link clicks
        document.querySelectorAll((window.CONSTANTS && window.CONSTANTS.SELECTORS.NAV_TAB) || '.nav-tab').forEach(tab => {
            tab.addEventListener('click', (e) => {
                e.preventDefault(); // Prevent default link behavior
                const routeName = tab.dataset.view;
                this.navigateTo(routeName);
            });
        });

        // Handle browser back/forward buttons
        window.addEventListener('popstate', (e) => this.handlePopState(e));

        // Navigate to route based on current URL on initial load
        const initialRoute = this.getRouteFromURL();
        logger.debug(`App: Initial route from URL: '${initialRoute}'`);
        
        // Set initial history state
        window.history.replaceState({ route: initialRoute }, '', `/${initialRoute}`);
        
        // Navigate to initial route
        this.navigateTo(initialRoute, false); // Don't update URL since we just set it
    }

    // Clean up cached components (call when app is shutting down)
    cleanup() {
        logger.debug('App: Cleaning up cached components...');
        
        this.componentCache.forEach((component, routeName) => {
            if (component.isMounted) {
                logger.debug(`App: Unmounting cached component '${routeName}'`);
                component.unmount();
            }
        });
        
        this.componentCache.clear();
        this.cachedViews.clear();
    }
}

// Global app instance
window.app = new App(); 