/**
 * CARL Control Panel - Frontend Application
 * Flask API Version
 */

// Toast Notification System
function showToast(message, type = 'info', duration = 4000) {
    // Create container if it doesn't exist
    let container = document.getElementById('toast-container');
    if (!container) {
        container = document.createElement('div');
        container.id = 'toast-container';
        document.body.appendChild(container);
    }

    const toast = document.createElement('div');
    toast.className = `toast toast-${type}`;
    toast.innerHTML = `
        <span class="toast-message">${message}</span>
        <button class="toast-close" onclick="this.parentElement.remove()">&times;</button>
    `;

    container.appendChild(toast);

    // Auto-remove after duration
    setTimeout(() => {
        toast.classList.add('toast-fade-out');
        setTimeout(() => toast.remove(), 300);
    }, duration);
}

// API Helper
async function api(endpoint, options = {}) {
    const url = `/api${endpoint}`;
    const config = {
        headers: {
            'Content-Type': 'application/json',
        },
        ...options,
    };
    if (config.body && typeof config.body === 'object') {
        config.body = JSON.stringify(config.body);
    }
    const response = await fetch(url, config);
    return response.json();
}

// State
let originalToggles = {};
let currentToggles = {};
let isConnected = false;
let hooksInstalled = false;
let previousView = 'settings';  // Track previous view for back navigation
let isManageWorkspacesMode = false;  // Track if we're in manage workspaces mode

// DOM Elements
const statusEl = document.getElementById('status');
const statusTextEl = statusEl.querySelector('.status-text');
const saveStatusEl = document.getElementById('save-status');
const workspacePathEl = document.getElementById('workspace-path');

// Views
const setupView = document.getElementById('setup-view');
const settingsView = document.getElementById('settings-view');
const addonsView = document.getElementById('addons-view');

// Setup elements
const workspaceInput = document.getElementById('workspace-input');
const initializeBtn = document.getElementById('btn-initialize');
const browseBtn = document.getElementById('btn-browse');
const setupErrorEl = document.getElementById('setup-error');
const setupTitleEl = document.getElementById('setup-title');
const setupSubtitleEl = document.getElementById('setup-subtitle');
const backFromSetupBtn = document.getElementById('btn-back-from-setup');

// Hooks elements
const hooksCard = document.getElementById('hooks-card');
const hooksStatusEl = document.getElementById('hooks-status');
const hooksStepInstall = document.getElementById('hooks-step-install');
const hooksStepWire = document.getElementById('hooks-step-wire');
const hooksComplete = document.getElementById('hooks-complete');
const installHooksBtn = document.getElementById('btn-install-hooks');
const installResultEl = document.getElementById('install-result');
const autoWireBtn = document.getElementById('btn-auto-wire');
const autoWireResultEl = document.getElementById('auto-wire-result');
const hooksSnippetEl = document.getElementById('hooks-snippet');
const claudePromptEl = document.getElementById('claude-prompt');

// Toggle elements mapped by key
const toggleInputs = {};

/**
 * Toggle settings accordion open/close state (by data-accordion ID)
 */
function toggleSettingsAccordion(accordionId) {
    const accordion = document.querySelector(`[data-accordion="${accordionId}"]`);
    if (accordion) {
        accordion.classList.toggle('open');
    }
}

/**
 * Position tooltip relative to trigger element
 */
function positionTooltip(event) {
    const trigger = event.currentTarget;
    const tooltip = trigger.querySelector('.rules-tooltip');
    if (!tooltip) return;

    const rect = trigger.getBoundingClientRect();
    const tooltipWidth = 320;

    // Position to the right of the icon
    let left = rect.right + 10;
    let top = rect.top - 10;

    // If it would go off the right edge, position to the left instead
    if (left + tooltipWidth > window.innerWidth - 20) {
        left = rect.left - tooltipWidth - 10;
        tooltip.style.setProperty('--arrow-side', 'right');
    } else {
        tooltip.style.setProperty('--arrow-side', 'left');
    }

    // Keep within vertical bounds
    if (top < 10) top = 10;
    if (top + 200 > window.innerHeight) top = window.innerHeight - 210;

    tooltip.style.left = left + 'px';
    tooltip.style.top = top + 'px';
}

/**
 * Initialize the application
 */
async function init() {
    // Get all toggle inputs
    document.querySelectorAll('[data-key]').forEach(input => {
        toggleInputs[input.dataset.key] = input;
        input.addEventListener('change', handleToggleChange);
    });

    // Setup view buttons
    initializeBtn.addEventListener('click', handleInitialize);
    browseBtn.addEventListener('click', handleBrowse);

    // Change workspace button
    const changeWorkspaceBtn = document.getElementById('btn-change-workspace');
    if (changeWorkspaceBtn) {
        changeWorkspaceBtn.addEventListener('click', handleChangeWorkspace);
    }

    // Back from setup button
    if (backFromSetupBtn) {
        backFromSetupBtn.addEventListener('click', handleBackFromSetup);
    }

    // Hooks buttons
    if (installHooksBtn) {
        installHooksBtn.addEventListener('click', handleInstallHooks);
    }
    if (autoWireBtn) {
        autoWireBtn.addEventListener('click', handleAutoWire);
    }

    // Hooks location radio options
    document.querySelectorAll('.hooks-location-options .radio-option').forEach(option => {
        option.addEventListener('click', () => {
            // Update visual selection
            document.querySelectorAll('.hooks-location-options .radio-option').forEach(o => o.classList.remove('selected'));
            option.classList.add('selected');
            // Update radio input
            const radio = option.querySelector('input[type="radio"]');
            if (radio) radio.checked = true;
        });
    });

    // Copy buttons for hooks
    const copySnippetBtn = document.getElementById('btn-copy-snippet');
    const copyPromptBtn = document.getElementById('btn-copy-prompt');
    if (copySnippetBtn) {
        copySnippetBtn.addEventListener('click', () => copyToClipboard(hooksSnippetEl.textContent, copySnippetBtn));
    }
    if (copyPromptBtn) {
        copyPromptBtn.addEventListener('click', () => copyToClipboard(claudePromptEl.textContent, copyPromptBtn));
    }

    // CLAUDE.md integration buttons
    const claudemdAutoBtn = document.getElementById('btn-claudemd-auto');
    const copyClaudemdSnippetBtn = document.getElementById('btn-copy-claudemd-snippet');
    const copyClaudemdPromptBtn = document.getElementById('btn-copy-claudemd-prompt');
    if (claudemdAutoBtn) {
        claudemdAutoBtn.addEventListener('click', handleClaudemdAutoAppend);
    }
    if (copyClaudemdSnippetBtn) {
        copyClaudemdSnippetBtn.addEventListener('click', () => {
            const snippetEl = document.getElementById('claudemd-snippet');
            if (snippetEl) copyToClipboard(snippetEl.textContent, copyClaudemdSnippetBtn);
        });
    }
    if (copyClaudemdPromptBtn) {
        copyClaudemdPromptBtn.addEventListener('click', () => {
            const promptEl = document.getElementById('claudemd-prompt');
            if (promptEl) copyToClipboard(promptEl.textContent, copyClaudemdPromptBtn);
        });
    }
    const claudemdChangeBtn = document.getElementById('btn-claudemd-change');
    const claudemdDismissBtn = document.getElementById('btn-claudemd-dismiss');
    if (claudemdChangeBtn) {
        claudemdChangeBtn.addEventListener('click', changeClaudemdPath);
    }
    if (claudemdDismissBtn) {
        claudemdDismissBtn.addEventListener('click', dismissClaudemd);
    }

    // Hide hooks card button
    const hideHooksBtn = document.getElementById('btn-hide-hooks');
    if (hideHooksBtn) {
        hideHooksBtn.addEventListener('click', () => {
            hooksCard.style.display = 'none';
        });
    }

    // Tab switching
    document.querySelectorAll('.tab-btn').forEach(btn => {
        btn.addEventListener('click', handleTabSwitch);
    });

    // Load initial data
    await loadStatus();

    // Refresh sessions button
    const refreshSessionsBtn = document.getElementById('btn-refresh-sessions');
    if (refreshSessionsBtn) {
        refreshSessionsBtn.addEventListener('click', loadSessions);
    }

    // Refresh optional hooks button
    const refreshOptionalHooksBtn = document.getElementById('btn-refresh-optional-hooks');
    if (refreshOptionalHooksBtn) {
        refreshOptionalHooksBtn.addEventListener('click', loadOptionalHooks);
    }

    // New flow: workspace -> .carl -> hooks -> settings
    const status = await api('/status');

    if (status.connected) {
        // Fully connected - show settings
        showView('settings');
        showMainNav();
        await loadToggles();
        await loadHooksStatus();
        await loadClaudemdStatus();
        await loadOptionalHooks();
        await loadSessions();
    } else if (status.needs_init) {
        // Has workspace but needs .carl initialization
        showView('setup');
        workspaceInput.value = status.workspace_path;
        showSetupError('Workspace selected. Click "Initialize CARL" to create .carl folder.');
        await loadWorkspaces();
    } else {
        // No workspace configured - first time setup
        showView('setup');
        await loadWorkspaces();
    }
}

/**
 * Show a specific view
 */
function showView(viewName) {
    setupView.classList.remove('active');
    settingsView.classList.remove('active');
    if (addonsView) addonsView.classList.remove('active');
    if (domainsView) domainsView.classList.remove('active');

    if (viewName === 'setup') {
        setupView.classList.add('active');
    } else if (viewName === 'settings') {
        settingsView.classList.add('active');
    } else if (viewName === 'addons') {
        if (addonsView) addonsView.classList.add('active');
    } else if (viewName === 'domains') {
        if (domainsView) domainsView.classList.add('active');
    }

    // Sync nav tab buttons with view (for non-setup views)
    if (viewName !== 'setup') {
        document.querySelectorAll('.nav-tab').forEach(btn => {
            btn.classList.toggle('active', btn.dataset.view === viewName);
        });
    }
}

/**
 * Load suggested workspace path
 */
async function loadSuggestedPath() {
    try {
        const result = await api('/suggested-path');
        if (result.path) {
            workspaceInput.value = result.path;
        }
    } catch (err) {
        console.error('Error getting suggested path:', err);
    }
}

/**
 * Handle initialize button click - Add workspace and create .carl
 */
async function handleInitialize() {
    const path = workspaceInput.value.trim();

    if (!path) {
        showSetupError('Please enter a workspace path');
        return;
    }

    initializeBtn.disabled = true;
    initializeBtn.textContent = 'Checking...';
    hideSetupError();

    try {
        // Step 0: Check if .claude exists
        const checkResult = await api('/workspace/check', {
            method: 'POST',
            body: { path }
        });

        if (!checkResult.valid) {
            showSetupError(checkResult.error || 'Invalid directory path');
            initializeBtn.disabled = false;
            initializeBtn.textContent = 'Initialize CARL';
            return;
        }

        // Check if CARL hooks are already configured globally BEFORE prompting for .claude bootstrap
        const globalHooksStatus = await api('/hooks/status');
        const globalHooksConfigured = globalHooksStatus.fully_configured;
        console.log('[CARL] Global hooks configured:', globalHooksConfigured);

        // If no .claude AND no global hooks, prompt user to create .claude first
        // But if global hooks ARE configured, .claude bootstrap is unnecessary
        if (!checkResult.has_claude && !globalHooksConfigured) {
            pendingBootstrapPath = path;
            pendingBootstrapAction = 'initialize'; // Flag to continue with init after bootstrap
            openBootstrapClaudeModal();
            initializeBtn.disabled = false;
            initializeBtn.textContent = 'Initialize CARL';
            return;
        }

        // Either .claude exists OR global hooks are configured - proceed with initialization
        await proceedWithInitialization(path);

    } catch (err) {
        console.error('Error initializing:', err);
        showSetupError('Error: ' + err.message);
        initializeBtn.disabled = false;
        initializeBtn.textContent = 'Initialize CARL';
    }
}

let pendingBootstrapAction = null; // 'initialize' or 'browse'

/**
 * Continue initialization after .claude is confirmed/created
 */
async function proceedWithInitialization(path) {
    initializeBtn.disabled = true;
    initializeBtn.textContent = 'Setting up...';

    try {
        // Step 1: Add workspace profile if not already added
        const status = await api('/status');
        if (!status.profile || status.profile.workspace_path !== path) {
            // Need to add this as a new workspace
            const name = path.split('/').pop() || path.split('\\').pop() || 'Workspace';
            const addResult = await api('/workspaces', {
                method: 'POST',
                body: { name, path }
            });
            if (!addResult.success) {
                showSetupError(addResult.error || 'Failed to add workspace');
                initializeBtn.disabled = false;
                initializeBtn.textContent = 'Initialize CARL';
                return;
            }
        }

        // Step 2: Initialize .carl
        const result = await api('/initialize', {
            method: 'POST',
            body: { path }
        });

        if (result.success) {
            // Reload status and check hooks
            await loadStatus();
            await loadHooksStatus();
            console.log('[CARL] After loadHooksStatus, hooks card display:', hooksCard?.style?.display);

            // If hooks are fully configured, go to settings
            const hooksResult = await api('/hooks/status');
            console.log('[CARL] Hooks status:', hooksResult);
            if (hooksResult.fully_configured) {
                await loadToggles();
                await loadClaudemdStatus();
                await loadOptionalHooks();
                await loadSessions();
                showView('settings');
                showMainNav();
            } else {
                // Hooks not fully configured - show settings with hooks card visible
                showView('settings');
                showMainNav();
                await loadToggles();
                await loadClaudemdStatus();
                await loadOptionalHooks();
                console.log('[CARL] After showing settings, hooks card display:', hooksCard?.style?.display);
            }
        } else if (result.can_reinit) {
            // .carl exists but may be corrupted/deleted - offer reinit
            if (confirm('CARL folder exists but may be incomplete. Reinitialize with fresh setup?\n\nThis will DELETE existing .carl and create a new one.')) {
                const reinitResult = await api('/initialize', {
                    method: 'POST',
                    body: { path, force: true }
                });
                if (reinitResult.success) {
                    await loadStatus();
                    await loadHooksStatus();
                    await loadToggles();
                    await loadClaudemdStatus();
                    await loadOptionalHooks();
                    await loadSessions();
                    showView('settings');
                    showMainNav();
                } else {
                    showSetupError(reinitResult.error || 'Failed to reinitialize CARL');
                }
            } else {
                showSetupError('Initialization cancelled. Remove existing .carl manually to start fresh.');
            }
        } else {
            showSetupError(result.error || 'Failed to initialize CARL');
        }
    } catch (err) {
        console.error('Error initializing:', err);
        showSetupError('Error: ' + err.message);
    }

    initializeBtn.disabled = false;
    initializeBtn.textContent = 'Initialize CARL';
}

/**
 * Handle browse existing button click - Open folder picker then connect
 */
let pendingBootstrapPath = null;

async function handleBrowse() {
    browseBtn.disabled = true;
    browseBtn.textContent = 'Select folder...';
    hideSetupError();

    try {
        // Open native folder picker
        const browseResult = await api('/browse-folder', { method: 'POST' });

        if (!browseResult.path) {
            // User cancelled
            browseBtn.disabled = false;
            browseBtn.textContent = 'Browse Existing';
            return;
        }

        // Update input with selected path
        workspaceInput.value = browseResult.path;
        browseBtn.textContent = 'Checking...';

        // Check workspace status first
        const checkResult = await api('/workspace/check', {
            method: 'POST',
            body: { path: browseResult.path }
        });

        if (!checkResult.valid) {
            showSetupError(checkResult.error || 'Invalid directory');
            browseBtn.disabled = false;
            browseBtn.textContent = 'Browse Existing';
            return;
        }

        // Check if CARL hooks are already configured globally
        const globalHooksStatus = await api('/hooks/status');
        const globalHooksConfigured = globalHooksStatus.fully_configured;

        // If no .claude AND no global hooks, prompt user to create .claude
        // But if global hooks ARE configured, .claude bootstrap is unnecessary
        if (!checkResult.has_claude && !globalHooksConfigured) {
            pendingBootstrapPath = browseResult.path;
            openBootstrapClaudeModal();
            browseBtn.disabled = false;
            browseBtn.textContent = 'Browse Existing';
            return;
        }

        // Either .claude exists OR global hooks are configured - proceed with connection
        await connectToWorkspace(browseResult.path);

    } catch (err) {
        console.error('Error browsing:', err);
        showSetupError('Error: ' + err.message);
    }

    browseBtn.disabled = false;
    browseBtn.textContent = 'Browse Existing';
}

/**
 * Connect to a workspace (after .claude is confirmed to exist)
 */
async function connectToWorkspace(path) {
    browseBtn.textContent = 'Connecting...';

    // Try to connect - if .carl exists, it will connect; if not, it will need init
    const result = await api('/workspaces/set', {
        method: 'POST',
        body: { path }
    });

    if (result.success) {
        await loadStatus();
        await loadToggles();
        await loadHooksStatus();
        await loadClaudemdStatus();
        await loadSessions();
        // Check for hook updates after workspace loads
        await checkHookVersions();
        showView('settings');
        showMainNav();
    } else if (result.error && result.error.includes('No valid .carl')) {
        // .claude exists but no .carl - show setup view with path populated
        workspaceInput.value = path;
        showSetupWarning('No CARL installation found. Click "Initialize CARL" to set up this workspace.');
    } else {
        showSetupError(result.error || 'Failed to connect to workspace');
    }

    browseBtn.disabled = false;
    browseBtn.textContent = 'Browse Existing';
}

/**
 * Bootstrap .claude modal functions
 */
function openBootstrapClaudeModal() {
    const modal = document.getElementById('bootstrap-claude-modal');
    if (modal) modal.style.display = 'flex';
}

function closeBootstrapClaudeModal() {
    const modal = document.getElementById('bootstrap-claude-modal');
    if (modal) modal.style.display = 'none';
    pendingBootstrapPath = null;
    pendingBootstrapAction = null;
}

async function confirmBootstrapClaude() {
    if (!pendingBootstrapPath) return;

    const path = pendingBootstrapPath;
    const action = pendingBootstrapAction;
    closeBootstrapClaudeModal();

    try {
        // Show progress on appropriate button
        if (action === 'initialize') {
            initializeBtn.disabled = true;
            initializeBtn.textContent = 'Creating .claude...';
        } else {
            browseBtn.disabled = true;
            browseBtn.textContent = 'Creating .claude...';
        }

        const result = await api('/workspace/bootstrap-claude', {
            method: 'POST',
            body: { path }
        });

        if (result.success) {
            showToast('Created .claude structure', 'success');
            // Continue with appropriate action
            if (action === 'initialize') {
                await proceedWithInitialization(path);
            } else {
                await connectToWorkspace(path);
            }
        } else {
            showSetupError(result.error || 'Failed to create .claude structure');
        }
    } catch (err) {
        console.error('Error bootstrapping .claude:', err);
        showSetupError('Error: ' + err.message);
    }

    // Reset buttons
    initializeBtn.disabled = false;
    initializeBtn.textContent = 'Initialize CARL';
    browseBtn.disabled = false;
    browseBtn.textContent = 'Browse Existing';
}

/**
 * Show setup error message
 */
function showSetupError(message) {
    setupErrorEl.textContent = message;
    setupErrorEl.classList.remove('warning');
    setupErrorEl.classList.add('visible');
}

/**
 * Show setup warning message (amber/orange instead of red)
 */
function showSetupWarning(message) {
    setupErrorEl.textContent = message;
    setupErrorEl.classList.add('visible', 'warning');
}

/**
 * Hide setup error message
 */
function hideSetupError() {
    setupErrorEl.classList.remove('visible', 'warning');
}

/**
 * Handle change workspace button click
 */
async function handleChangeWorkspace() {
    // Track current view for back navigation
    const currentView = getCurrentView();
    if (currentView !== 'setup') {
        previousView = currentView;
    }

    // Enter manage workspaces mode
    isManageWorkspacesMode = true;

    // Update UI for manage workspaces mode
    if (setupTitleEl) setupTitleEl.textContent = 'Manage Workspaces';
    if (setupSubtitleEl) setupSubtitleEl.textContent = 'Switch between workspaces or add a new one';
    if (backFromSetupBtn) backFromSetupBtn.style.display = 'flex';

    // Load configured workspaces and show setup view
    await loadWorkspaces();
    showView('setup');
    hideMainNav();
}

/**
 * Handle back button from setup/manage workspaces
 */
function handleBackFromSetup() {
    // Exit manage workspaces mode
    isManageWorkspacesMode = false;

    // Reset UI to default setup mode
    if (setupTitleEl) setupTitleEl.textContent = 'Welcome to CARL Control Panel';
    if (setupSubtitleEl) setupSubtitleEl.textContent = 'No CARL installation found. Let\'s set one up!';
    if (backFromSetupBtn) backFromSetupBtn.style.display = 'none';

    // Remove danger zone section
    const dangerZone = document.getElementById('danger-zone-section');
    if (dangerZone) dangerZone.remove();

    // Return to previous view
    showView(previousView);
    showMainNav();
}

/**
 * Get the current active view name
 */
function getCurrentView() {
    if (settingsView && settingsView.classList.contains('active')) return 'settings';
    if (addonsView && addonsView.classList.contains('active')) return 'addons';
    const domainsView = document.getElementById('domains-view');
    if (domainsView && domainsView.classList.contains('active')) return 'domains';
    return 'settings';
}

/**
 * Load existing CARL installations for the setup view
 */
async function loadExistingInstallations() {
    try {
        const result = await api('/existing-installations');
        const installations = result.installations || [];
        const currentPath = result.current_path;

        // If we have a current path, prefill with it
        if (currentPath) {
            workspaceInput.value = currentPath;
        } else if (installations.length > 0) {
            // Prefill with first found installation
            workspaceInput.value = installations[0].path;
        } else {
            // Fall back to suggested path for new installation
            await loadSuggestedPath();
        }

        // Show existing installations list if any found
        renderExistingInstallations(installations, currentPath);
    } catch (err) {
        console.error('Error loading existing installations:', err);
        await loadSuggestedPath();
    }
}

/**
 * Render list of existing CARL installations
 */
function renderExistingInstallations(installations, currentPath) {
    // Find or create the existing installations container
    let container = document.getElementById('existing-installations');
    if (!container) {
        // Create container after the form-group
        const formGroup = document.querySelector('.form-group');
        container = document.createElement('div');
        container.id = 'existing-installations';
        container.className = 'existing-installations';
        formGroup.parentNode.insertBefore(container, formGroup.nextSibling);
    }

    if (installations.length === 0) {
        container.innerHTML = '';
        container.style.display = 'none';
        return;
    }

    container.style.display = 'block';
    container.innerHTML = `
        <p class="form-hint" style="margin-bottom: 8px;">Found existing installations:</p>
        <div class="installation-list">
            ${installations.map(inst => `
                <button type="button" class="installation-btn ${inst.path === currentPath ? 'current' : ''}"
                        onclick="selectInstallation('${inst.path.replace(/'/g, "\\'")}')">
                    <span class="installation-name">${inst.workspace_name}</span>
                    <span class="installation-path">${inst.path}</span>
                    ${inst.path === currentPath ? '<span class="current-badge">current</span>' : ''}
                </button>
            `).join('')}
        </div>
    `;
}

/**
 * Select an existing installation
 */
function selectInstallation(path) {
    workspaceInput.value = path;
    // Automatically try to browse to it
    handleBrowse();
}

/**
 * Load connection status
 */
async function loadStatus() {
    try {
        const result = await api('/status');

        if (result.connected) {
            isConnected = true;
            statusEl.className = 'status connected';
            statusTextEl.textContent = 'Connected';
            workspacePathEl.textContent = result.info.carl_path;
        } else if (result.needs_init) {
            // Has workspace profile but .carl needs initialization
            isConnected = false;
            statusEl.className = 'status disconnected';
            statusTextEl.textContent = 'Needs Setup';
            workspacePathEl.textContent = result.workspace_path + ' (needs .carl)';
        } else {
            // No workspace configured
            isConnected = false;
            statusEl.className = 'status disconnected';
            statusTextEl.textContent = 'No Workspace';
            workspacePathEl.textContent = 'Select a workspace to get started';
        }
    } catch (err) {
        console.error('Error loading status:', err);
        isConnected = false;
        statusEl.className = 'status disconnected';
        statusTextEl.textContent = 'Error';
    }
}

/**
 * Load configured workspaces
 */
async function loadWorkspaces() {
    try {
        const result = await api('/workspaces');
        const workspaces = result.workspaces || [];

        if (workspaces.length > 0) {
            // Show existing workspaces
            renderWorkspaceList(workspaces, result.active_id);
        } else {
            // No workspaces - show empty state
            hideWorkspaceList();
        }
    } catch (err) {
        console.error('Error loading workspaces:', err);
    }
}

/**
 * Render workspace list for selection/switching
 */
function renderWorkspaceList(workspaces, activeId) {
    let container = document.getElementById('workspace-list');
    if (!container) {
        const formGroup = document.querySelector('.form-group');
        container = document.createElement('div');
        container.id = 'workspace-list';
        container.className = 'existing-installations';
        formGroup.parentNode.insertBefore(container, formGroup);
    }

    // Find the active workspace for showing danger zone
    const activeWorkspace = workspaces.find(ws => ws.id === activeId);

    container.style.display = 'block';
    container.innerHTML = `
        <p class="form-hint" style="margin-bottom: 8px;">Configured workspaces:</p>
        <div class="installation-list">
            ${workspaces.map(ws => `
                <div class="installation-item ${ws.id === activeId ? 'current' : ''} ${!ws.is_valid ? 'invalid' : ''}">
                    <button type="button" class="installation-btn"
                            onclick="switchWorkspace('${ws.id}')">
                        <span class="installation-name">${ws.name}</span>
                        <span class="installation-path">${ws.workspace_path}</span>
                        ${ws.id === activeId ? '<span class="current-badge">active</span>' : ''}
                        ${!ws.is_valid ? '<span class="error-badge">needs setup</span>' : ''}
                    </button>
                    ${ws.id !== activeId ? `<button type="button" class="btn-remove-workspace" onclick="removeWorkspace('${ws.id}', '${ws.name}')" title="Remove from list">×</button>` : ''}
                </div>
            `).join('')}
        </div>
        <p class="form-hint" style="margin-top: 12px;">Or add a new workspace:</p>
    `;

    // Add Danger Zone section for active workspace
    renderDangerZone(activeWorkspace);
}

/**
 * Hide workspace list
 */
function hideWorkspaceList() {
    const container = document.getElementById('workspace-list');
    if (container) {
        container.style.display = 'none';
    }
}

/**
 * Switch to a different workspace
 */
async function switchWorkspace(profileId) {
    try {
        const result = await api('/workspaces/switch', {
            method: 'POST',
            body: { profile_id: profileId }
        });
        if (result.success) {
            // Reload entire app state
            await loadStatus();
            if (result.connected) {
                showView('settings');
                showMainNav();
                await loadToggles();
                await loadHooksStatus();
                await loadClaudemdStatus();
                await loadSessions();
            } else {
                // Workspace needs setup - populate the path field
                showView('setup');
                hideMainNav();
                if (result.workspace_path) {
                    workspaceInput.value = result.workspace_path;
                    showSetupError('Workspace selected. Click "Initialize CARL" to create .carl folder.');
                }
                await loadWorkspaces();
            }
        } else {
            showSetupError(result.error || 'Failed to switch workspace');
        }
    } catch (err) {
        console.error('Error switching workspace:', err);
        showSetupError('Error: ' + err.message);
    }
}

/**
 * Remove a workspace from the list (does not delete files)
 */
let pendingRemoveWorkspace = null;

function removeWorkspace(profileId, profileName) {
    pendingRemoveWorkspace = { id: profileId, name: profileName };
    const modal = document.getElementById('remove-workspace-modal');
    const nameEl = document.getElementById('remove-workspace-name');
    if (nameEl) nameEl.textContent = profileName;
    if (modal) modal.style.display = 'flex';
}

function closeRemoveWorkspaceModal() {
    const modal = document.getElementById('remove-workspace-modal');
    if (modal) modal.style.display = 'none';
    pendingRemoveWorkspace = null;
}

async function confirmRemoveWorkspace() {
    if (!pendingRemoveWorkspace) return;

    const { id, name } = pendingRemoveWorkspace;
    closeRemoveWorkspaceModal();

    try {
        const result = await api(`/workspaces/${id}`, { method: 'DELETE' });
        if (result.success) {
            showToast(`Removed "${name}" from list`, 'success');
            await loadWorkspaces();
        } else {
            showToast(result.error || 'Failed to remove workspace', 'error');
        }
    } catch (err) {
        console.error('Error removing workspace:', err);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Load toggle values from manifest
 */
async function loadToggles() {
    try {
        const result = await api('/toggles');

        if (result.error) {
            console.error('Error loading toggles:', result.error);
            disableToggles();
            return;
        }

        originalToggles = { ...result.toggles };
        currentToggles = { ...result.toggles };

        // Update UI
        for (const [key, value] of Object.entries(result.toggles)) {
            if (toggleInputs[key]) {
                toggleInputs[key].checked = value;
                toggleInputs[key].disabled = false;
            }
        }
    } catch (err) {
        console.error('Error loading toggles:', err);
        disableToggles();
    }
}

/**
 * Disable all toggles (when not connected)
 */
function disableToggles() {
    for (const input of Object.values(toggleInputs)) {
        input.disabled = true;
    }
}

/**
 * Handle toggle change - auto-save immediately
 */
async function handleToggleChange(event) {
    const key = event.target.dataset.key;
    const value = event.target.checked;
    const previousValue = currentToggles[key];

    currentToggles[key] = value;

    try {
        const result = await api('/toggles', {
            method: 'POST',
            body: { toggles: currentToggles }
        });

        if (result.success) {
            originalToggles = { ...currentToggles };
            showSaveStatus('Saved!', false);
        } else {
            // Revert on error
            currentToggles[key] = previousValue;
            event.target.checked = previousValue;
            showSaveStatus(result.error || 'Save failed', true);
        }
    } catch (err) {
        console.error('Error saving toggle:', err);
        // Revert on error
        currentToggles[key] = previousValue;
        event.target.checked = previousValue;
        showSaveStatus('Error saving', true);
    }
}

/**
 * Show save status message
 */
function showSaveStatus(message, isError) {
    saveStatusEl.textContent = message;
    saveStatusEl.className = isError ? 'save-status-inline error' : 'save-status-inline';

    // Clear after 3 seconds
    setTimeout(clearSaveStatus, 3000);
}

/**
 * Clear save status message
 */
function clearSaveStatus() {
    saveStatusEl.textContent = '';
    saveStatusEl.className = 'save-status-inline';
}

// ---- Hooks Functions ----

/**
 * Load hooks installation status
 * Handles three states:
 * 1. Hooks not installed -> show install step
 * 2. Hooks installed but not wired -> show wire step
 * 3. Hooks installed AND wired -> hide card entirely
 */
async function loadHooksStatus() {
    // Ensure the hooks card element exists
    if (!hooksCard) {
        console.error('[CARL] hooksCard element not found in DOM!');
        return;
    }

    try {
        const result = await api('/hooks/status');
        console.log('[CARL] loadHooksStatus API result:', result);

        const allInstalled = result.all_installed || false;
        const wired = result.wired || false;
        const fullyConfigured = result.fully_configured || false;

        console.log('[CARL] allInstalled:', allInstalled, 'wired:', wired, 'fullyConfigured:', fullyConfigured);

        hooksInstalled = allInstalled;

        if (fullyConfigured) {
            // Fully configured - hide the card entirely
            console.log('[CARL] Hooks fully configured, hiding card');
            hooksCard.style.display = 'none';
        } else if (allInstalled && !wired) {
            // Hooks installed but not wired - show wiring step
            hooksCard.style.display = 'block';
            hooksStepInstall.style.display = 'none';
            hooksStepWire.style.display = 'block';
            hooksComplete.style.display = 'none';

            // Update status
            hooksStatusEl.querySelector('.status-text').textContent = 'Hooks installed - wire them to settings.json';
            hooksStatusEl.classList.add('installed');

            // Load the snippets
            await loadHooksSnippets();
        } else {
            // Hooks not installed - show install step
            console.log('[CARL] Hooks not installed/wired, showing install card');
            hooksCard.style.display = 'block';
            hooksStepInstall.style.display = 'block';
            hooksStepWire.style.display = 'none';
            hooksComplete.style.display = 'none';

            const hooks = result.hooks || {};
            const installedCount = Object.values(hooks).filter(h => h.installed).length;
            const totalCount = Object.keys(hooks).length;
            hooksStatusEl.querySelector('.status-text').textContent = `${installedCount}/${totalCount} hooks installed`;
            hooksStatusEl.classList.remove('installed');
            console.log('[CARL] hooksCard.style.display is now:', hooksCard.style.display);
        }
    } catch (err) {
        console.error('Error loading hooks status:', err);
        // Show the card with install step on error (don't hide it silently)
        hooksCard.style.display = 'block';
        hooksStepInstall.style.display = 'block';
        hooksStepWire.style.display = 'none';
        hooksComplete.style.display = 'none';
        hooksStatusEl.querySelector('.status-text').textContent = 'Unable to check status - try installing hooks';
        hooksStatusEl.classList.remove('installed');
    }
}

/**
 * Load hooks snippets for manual copy / Claude prompt
 */
async function loadHooksSnippets() {
    try {
        const [snippetResult, promptResult] = await Promise.all([
            api('/hooks/snippet'),
            api('/hooks/prompt')
        ]);

        if (snippetResult.snippet) {
            hooksSnippetEl.textContent = snippetResult.snippet;
        }
        if (promptResult.prompt) {
            claudePromptEl.textContent = promptResult.prompt;
        }
    } catch (err) {
        console.error('Error loading hooks snippets:', err);
    }
}

/**
 * Handle install hooks button click
 */
async function handleInstallHooks() {
    installHooksBtn.disabled = true;
    installHooksBtn.textContent = 'Installing...';
    installResultEl.textContent = '';
    installResultEl.className = 'result-message';

    // Get selected location (global or project)
    const selectedLocation = document.querySelector('input[name="hooks-location"]:checked')?.value || 'global';

    try {
        const result = await api('/hooks/install', {
            method: 'POST',
            body: { location: selectedLocation }
        });

        if (result.success) {
            installResultEl.textContent = `Installed ${result.installed.length} hooks to ${result.hooks_dir}`;
            installResultEl.classList.add('success');

            // Move to wiring step
            await loadHooksStatus();
        } else {
            installResultEl.textContent = result.error || 'Installation failed';
            installResultEl.classList.add('error');
        }
    } catch (err) {
        console.error('Error installing hooks:', err);
        installResultEl.textContent = 'Error: ' + err.message;
        installResultEl.classList.add('error');
    }

    installHooksBtn.disabled = false;
    installHooksBtn.textContent = 'Install Hooks';
}

/**
 * Handle auto-wire button click
 */
async function handleAutoWire() {
    autoWireBtn.disabled = true;
    autoWireBtn.textContent = 'Wiring...';
    autoWireResultEl.textContent = '';
    autoWireResultEl.className = 'result-message';

    try {
        const result = await api('/hooks/wire', { method: 'POST' });

        if (result.success) {
            autoWireResultEl.textContent = `Updated ${result.settings_path}`;
            autoWireResultEl.classList.add('success');

            // Refresh status - this will hide the card since fully_configured will be true
            await loadHooksStatus();
        } else {
            autoWireResultEl.textContent = result.error || 'Wiring failed';
            autoWireResultEl.classList.add('error');
        }
    } catch (err) {
        console.error('Error auto-wiring hooks:', err);
        autoWireResultEl.textContent = 'Error: ' + err.message;
        autoWireResultEl.classList.add('error');
    }

    autoWireBtn.disabled = false;
    autoWireBtn.textContent = 'Auto-append to settings.json';
}

/**
 * Handle tab switching
 */
function handleTabSwitch(event) {
    const tabName = event.target.dataset.tab;

    // Update active tab button
    document.querySelectorAll('.tab-btn').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.tab === tabName);
    });

    // Update active tab content
    document.querySelectorAll('.tab-content').forEach(content => {
        content.classList.toggle('active', content.id === `tab-${tabName}`);
    });
}

/**
 * Copy text to clipboard
 */
async function copyToClipboard(text, buttonEl) {
    try {
        await navigator.clipboard.writeText(text);
        const originalText = buttonEl.textContent;
        buttonEl.textContent = 'Copied!';
        setTimeout(() => {
            buttonEl.textContent = originalText;
        }, 2000);
    } catch (err) {
        console.error('Error copying to clipboard:', err);
        buttonEl.textContent = 'Failed';
        setTimeout(() => {
            buttonEl.textContent = 'Copy';
        }, 2000);
    }
}

// ---- CLAUDE.md Integration Functions ----

const claudemdCard = document.getElementById('claudemd-card');
const claudemdStatusEl = document.getElementById('claudemd-status');
const claudemdStepSetup = document.getElementById('claudemd-step-setup');
const claudemdComplete = document.getElementById('claudemd-complete');
const claudemdTargetPath = document.getElementById('claudemd-target-path');
let currentClaudemdPath = null; // Track custom path override

/**
 * Load CLAUDE.md integration status
 * Shows card if CARL block is missing from CLAUDE.md
 */
async function loadClaudemdStatus() {
    console.log('[CARL] loadClaudemdStatus called, isConnected:', isConnected);
    if (!isConnected) {
        if (claudemdCard) claudemdCard.style.display = 'none';
        return;
    }

    try {
        const result = await api('/claudemd/status');
        console.log('[CARL] claudemd/status result:', result);

        if (result.error) {
            console.log('[CARL] claudemd/status error, hiding card');
            if (claudemdCard) claudemdCard.style.display = 'none';
            return;
        }

        // Update path display
        if (claudemdTargetPath && result.path) {
            claudemdTargetPath.textContent = result.path;
            currentClaudemdPath = result.path;
        }

        // Check if dismissed
        if (result.dismissed) {
            console.log('[CARL] claudemd dismissed, hiding card');
            if (claudemdCard) claudemdCard.style.display = 'none';
            return;
        }

        if (result.status === 'configured') {
            // CARL block exists - hide the card
            console.log('[CARL] claudemd status=configured, hiding card');
            if (claudemdCard) claudemdCard.style.display = 'none';
        } else {
            console.log('[CARL] claudemd needs setup, showing card. status:', result.status);
            // Need to set up CARL integration
            if (claudemdCard) {
                claudemdCard.style.display = 'block';
                claudemdStepSetup.style.display = 'block';
                claudemdComplete.style.display = 'none';

                // Update status text
                const statusText = claudemdStatusEl?.querySelector('.status-text');
                if (statusText) {
                    if (result.status === 'missing') {
                        statusText.textContent = 'CLAUDE.md not found - Claude ignores CARL rules!';
                    } else {
                        statusText.textContent = 'CARL block missing from CLAUDE.md';
                    }
                }

                // Load snippets for manual/claude tabs
                await loadClaudemdSnippets();
            }
        }
    } catch (err) {
        if (claudemdCard) claudemdCard.style.display = 'none';
    }
}

/**
 * Change CLAUDE.md target path
 */
async function changeClaudemdPath() {
    const btn = document.getElementById('btn-claudemd-change');
    if (btn) btn.disabled = true;

    try {
        const result = await api('/browse-file', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ filter: 'CLAUDE.md' })
        });

        if (result.path) {
            // Update the custom path
            const setResult = await api('/claudemd/set-path', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ path: result.path })
            });

            if (setResult.success) {
                await loadClaudemdStatus();
                showToast('CLAUDE.md path updated', 'success');
            } else {
                showToast(setResult.error || 'Failed to set path', 'error');
            }
        }
    } catch (err) {
        console.error('Error changing CLAUDE.md path:', err);
    }

    if (btn) btn.disabled = false;
}

/**
 * Dismiss CLAUDE.md integration prompt
 */
async function dismissClaudemd() {
    try {
        const result = await api('/claudemd/dismiss', { method: 'POST' });
        if (result.success) {
            if (claudemdCard) claudemdCard.style.display = 'none';
            showToast('CLAUDE.md setup dismissed', 'info');
        }
    } catch (err) {
        console.error('Error dismissing CLAUDE.md prompt:', err);
    }
}

/**
 * Load CLAUDE.md snippets for manual copy / Claude prompt
 */
async function loadClaudemdSnippets() {
    try {
        const [snippetResult, promptResult] = await Promise.all([
            api('/claudemd/snippet'),
            api('/claudemd/prompt')
        ]);

        const claudemdSnippetEl = document.getElementById('claudemd-snippet');
        const claudemdPromptEl = document.getElementById('claudemd-prompt');

        if (snippetResult.snippet && claudemdSnippetEl) {
            claudemdSnippetEl.textContent = snippetResult.snippet;
        }
        if (promptResult.prompt && claudemdPromptEl) {
            claudemdPromptEl.textContent = promptResult.prompt;
        }
    } catch (err) {
        console.error('Error loading CLAUDE.md snippets:', err);
    }
}

/**
 * Handle auto-append CARL block to CLAUDE.md
 */
async function handleClaudemdAutoAppend() {
    const btn = document.getElementById('btn-claudemd-auto');
    const resultEl = document.getElementById('claudemd-auto-result');

    if (btn) {
        btn.disabled = true;
        btn.textContent = 'Adding...';
    }
    if (resultEl) {
        resultEl.textContent = '';
        resultEl.className = 'result-message';
    }

    try {
        const result = await api('/claudemd/auto-append', { method: 'POST' });

        if (result.success) {
            if (resultEl) {
                resultEl.textContent = `Added CARL block to ${result.path}`;
                resultEl.classList.add('success');
            }
            // Refresh status - this will hide the card
            await loadClaudemdStatus();
        } else {
            if (resultEl) {
                resultEl.textContent = result.error || 'Failed to add CARL block';
                resultEl.classList.add('error');
            }
        }
    } catch (err) {
        console.error('Error adding CARL block:', err);
        if (resultEl) {
            resultEl.textContent = 'Error: ' + err.message;
            resultEl.classList.add('error');
        }
    }

    if (btn) {
        btn.disabled = false;
        btn.textContent = 'Auto-add to CLAUDE.md';
    }
}

// ---- Optional Hooks Functions ----

const optionalHooksListEl = document.getElementById('optional-hooks-list');

// Store loaded hooks for reference
let loadedOptionalHooks = [];

/**
 * Load and render optional hooks status
 */
async function loadOptionalHooks() {
    if (!isConnected) {
        optionalHooksListEl.innerHTML = '<div class="no-hooks">Connect to a workspace first</div>';
        return;
    }

    optionalHooksListEl.innerHTML = '<div class="loading">Loading resources...</div>';

    try {
        const result = await api('/resources');

        if (result.error) {
            optionalHooksListEl.innerHTML = `<div class="error">${result.error}</div>`;
            return;
        }

        const resources = result.resources || [];
        loadedOptionalHooks = resources; // Keep variable name for compatibility

        // Hide entire Resources section if no enabled resources available
        const resourcesCard = document.getElementById('optional-hooks-card');
        if (resources.length === 0) {
            if (resourcesCard) resourcesCard.style.display = 'none';
            return;
        }
        if (resourcesCard) resourcesCard.style.display = '';

        // Render each resource
        optionalHooksListEl.innerHTML = '';
        for (const resource of resources) {
            const resourceEl = renderResource(resource);
            optionalHooksListEl.appendChild(resourceEl);
            // Load snippet AFTER element is in DOM
            if (resource.status === 'installed' && resource.types.includes('hook')) {
                loadResourceSnippet(resource.id);
            }
        }

        // Also update Settings page resource toggles section
        updateSettingsResourceToggles(resources);
    } catch (err) {
        console.error('Error loading resources:', err);
        optionalHooksListEl.innerHTML = `<div class="error">Error: ${err.message || 'Failed to load resources'}</div>`;
    }
}

/**
 * Render a single resource card with three-state UI
 * Supports hooks, skills, and commands with type badges
 */
function renderResource(resource) {
    const div = document.createElement('div');
    div.className = `optional-hook-item ${resource.status === 'wired' ? 'active' : ''}`;
    div.dataset.resourceId = resource.id;

    // Status badge text and class
    let statusText, statusClass;
    if (resource.status === 'wired') {
        statusText = 'ACTIVE';
        statusClass = 'active';
    } else if (resource.status === 'installed') {
        statusText = 'INSTALLED';
        statusClass = 'partial';
    } else {
        statusText = 'NOT INSTALLED';
        statusClass = 'inactive';
    }

    let actionsHtml = '';
    const hasHooks = resource.types.includes('hook');

    if (resource.status === 'not_installed') {
        // Show install button
        actionsHtml = `
            <button class="btn btn-small btn-primary" onclick="installResource('${resource.id}')">
                Install
            </button>
        `;
    } else if (resource.status === 'installed' && hasHooks) {
        // Show wiring flow for hooks
        actionsHtml = `
            <div class="hooks-step">
                <h3>Wire to Settings</h3>
                <p>Add hook to <code>~/.claude/settings.json</code></p>
                <div style="display: flex; gap: 8px; margin-bottom: 12px;">
                    <button class="btn btn-small btn-primary" onclick="wireResource('${resource.id}')">
                        Auto-Append
                    </button>
                    <button class="btn btn-small btn-secondary" onclick="copyResourceSnippet('${resource.id}')">
                        Copy Snippet
                    </button>
                </div>
                <div class="code-block" id="snippet-${resource.id}">
                    <pre>Loading snippet...</pre>
                </div>
            </div>
        `;
    } else if (resource.status === 'wired' && hasHooks) {
        // Show global toggle and uninstall
        actionsHtml = `
            <div class="override-row" style="border-bottom: none; padding: 8px 0;">
                <div class="override-info">
                    <span class="override-label">Global Enabled</span>
                </div>
                <div class="override-toggle">
                    <label class="switch">
                        <input type="checkbox" ${resource.global_enabled ? 'checked' : ''}
                               onchange="toggleResource('${resource.id}', this.checked)">
                        <span class="slider"></span>
                    </label>
                </div>
            </div>
            <div style="display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px;">
                <button class="btn btn-small btn-secondary" onclick="uninstallResource('${resource.id}', false)" title="Remove from settings.json only">
                    Disable
                </button>
                <button class="btn btn-small btn-danger" onclick="uninstallResource('${resource.id}', true)" title="Delete file and remove from settings">
                    Delete
                </button>
            </div>
        `;
    } else if (resource.status === 'installed' && !hasHooks) {
        // Non-hook resource (skill/command) - just show uninstall
        actionsHtml = `
            <div style="display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px;">
                <button class="btn btn-small btn-danger" onclick="uninstallResource('${resource.id}', true)">
                    Uninstall
                </button>
            </div>
        `;
    }

    // Type badges - show all types
    const typeBadges = resource.types.map(t =>
        `<span class="resource-type-badge resource-type-${t}">${t.toUpperCase()}</span>`
    ).join('');

    // Trigger info (for hooks)
    let triggerHtml = '';
    if (hasHooks && resource.hooks) {
        const hookNames = Object.keys(resource.hooks);
        if (hookNames.length > 0) {
            const hookType = resource.hooks[hookNames[0]].hook_type || 'UserPromptSubmit';
            triggerHtml = `<div class="optional-hook-meta">Trigger: <code>${hookType}</code></div>`;
        }
    }

    div.innerHTML = `
        <div class="optional-hook-info">
            <span class="optional-hook-name">${resource.name}</span>
            <span class="optional-hook-badges">
                ${typeBadges}
                <span class="optional-hook-status ${statusClass}">${statusText}</span>
            </span>
        </div>
        <div class="optional-hook-description">${resource.description}</div>
        ${triggerHtml}
        ${actionsHtml}
    `;

    return div;
}

// Keep old function for backward compatibility
function renderOptionalHook(hook) {
    return renderResource(hook);
}

/**
 * Load snippet preview for an installed resource
 */
async function loadResourceSnippet(resourceId) {
    try {
        const result = await api(`/resources/snippet?resource_id=${encodeURIComponent(resourceId)}`);
        const snippetEl = document.getElementById(`snippet-${resourceId}`);
        if (snippetEl && result.success) {
            snippetEl.innerHTML = `<pre>${escapeHtml(result.snippet)}</pre>`;
        }
    } catch (err) {
        console.error('Error loading snippet:', err);
    }
}

/**
 * Install a resource
 */
async function installResource(resourceId) {
    // Show modal to choose install location
    const modal = document.createElement('div');
    modal.className = 'modal-backdrop';
    modal.innerHTML = `
        <div class="modal" style="max-width: 400px;">
            <div class="modal-header">
                <h2>Install Location</h2>
                <button class="modal-close" onclick="this.closest('.modal-backdrop').remove()">&times;</button>
            </div>
            <div class="modal-body">
                <p style="margin-bottom: 16px;">Where do you want to install this resource?</p>
                <div style="display: flex; flex-direction: column; gap: 12px;">
                    <button class="btn btn-primary" onclick="doInstallResource('${resourceId}', 'global', this)">
                        <strong>Global</strong> (~/.claude/)
                    </button>
                    <button class="btn btn-secondary" onclick="doInstallResource('${resourceId}', 'project', this)">
                        <strong>Project</strong> ({workspace}/.claude/)
                    </button>
                </div>
                <p style="margin-top: 12px; font-size: 0.85rem; color: var(--text-muted);">
                    Global installs are available in all projects. Project installs are scoped to the current workspace.
                </p>
            </div>
        </div>
    `;
    document.body.appendChild(modal);
}

async function doInstallResource(resourceId, target, btn) {
    const modal = btn.closest('.modal-backdrop');
    const buttons = modal.querySelectorAll('button');
    buttons.forEach(b => b.disabled = true);
    btn.textContent = 'Installing...';

    try {
        const result = await api('/resources/install', {
            method: 'POST',
            body: { resource_id: resourceId, target: target }
        });

        modal.remove();

        if (result.success) {
            const location = target === 'global' ? 'globally' : 'to project';
            showToast(`Resource installed ${location}`, 'success');
            await loadOptionalHooks();
        } else {
            showToast(result.error || 'Install failed', 'error');
        }
    } catch (err) {
        modal.remove();
        showToast('Install failed', 'error');
        btn.disabled = false;
        btn.textContent = 'Install';
    }
}

/**
 * Wire a resource's hooks to settings.json
 */
async function wireResource(resourceId) {
    const btn = event.target;
    btn.disabled = true;
    btn.textContent = 'Wiring...';

    try {
        const result = await api('/resources/wire', {
            method: 'POST',
            body: { resource_id: resourceId }
        });

        if (result.success) {
            showToast('Resource wired successfully', 'success');
            await loadOptionalHooks();
        } else {
            showToast(result.error || 'Wiring failed', 'error');
            btn.disabled = false;
            btn.textContent = 'Auto-Append';
        }
    } catch (err) {
        showToast('Wiring failed', 'error');
        btn.disabled = false;
        btn.textContent = 'Auto-Append';
    }
}

/**
 * Copy resource snippet to clipboard
 */
async function copyResourceSnippet(resourceId) {
    try {
        const result = await api(`/resources/snippet?resource_id=${encodeURIComponent(resourceId)}`);
        if (result.success) {
            await navigator.clipboard.writeText(result.snippet);
            showToast('Snippet copied to clipboard', 'success');
        } else {
            showToast('Failed to get snippet', 'error');
        }
    } catch (err) {
        showToast('Failed to copy snippet', 'error');
    }
}

/**
 * Toggle a resource's global enabled state
 */
async function toggleResource(resourceId, enabled) {
    try {
        const result = await api('/resources/toggle', {
            method: 'POST',
            body: { resource_id: resourceId, enabled: enabled }
        });

        if (result.success) {
            showToast(`Resource ${enabled ? 'enabled' : 'disabled'}`, 'success');
        } else {
            showToast(result.error || 'Toggle failed', 'error');
            await loadOptionalHooks(); // Refresh to revert checkbox
        }
    } catch (err) {
        showToast('Toggle failed', 'error');
        await loadOptionalHooks();
    }
}

/**
 * Uninstall a resource
 */
async function uninstallResource(resourceId, deleteFiles = false) {
    try {
        const result = await api('/resources/uninstall', {
            method: 'POST',
            body: { resource_id: resourceId, delete_files: deleteFiles }
        });

        if (result.success) {
            showToast(deleteFiles ? 'Resource deleted' : 'Resource disabled', 'success');
            await loadOptionalHooks();
        } else {
            showToast(result.error || 'Uninstall failed', 'error');
        }
    } catch (err) {
        showToast('Uninstall failed', 'error');
    }
}

/**
 * Update Settings page with resource toggles (for installed hook resources)
 */
function updateSettingsResourceToggles(resources) {
    // Filter for wired hook resources
    const wiredResources = resources.filter(r => r.status === 'wired' && r.types.includes('hook'));
    const resourceSection = document.getElementById('installed-resources-settings');

    if (!resourceSection) return;

    if (wiredResources.length === 0) {
        resourceSection.style.display = 'none';
        return;
    }

    resourceSection.style.display = 'block';
    const listEl = document.getElementById('resource-toggles-list');
    if (!listEl) return;

    // Build toggle HTML for each resource
    listEl.innerHTML = wiredResources.map(resource => {
        // Get hook type from first hook in the resource
        let hookType = 'Hook';
        if (resource.hooks) {
            const hookNames = Object.keys(resource.hooks);
            if (hookNames.length > 0) {
                hookType = resource.hooks[hookNames[0]].hook_type || 'UserPromptSubmit';
            }
        }

        return `
            <div class="toggle-item" data-resource="${resource.id}">
                <div class="toggle-info">
                    <label>${resource.name}</label>
                    <span class="toggle-description">Trigger: ${hookType}</span>
                </div>
                <label class="switch">
                    <input type="checkbox" ${resource.global_enabled ? 'checked' : ''}
                           data-resource="${resource.id}"
                           onchange="toggleResource('${resource.id}', this.checked)">
                    <span class="slider"></span>
                </label>
            </div>
        `;
    }).join('');
}

/**
 * Load snippet preview for an installed hook (legacy compatibility)
 */
async function loadSnippetPreview(hookName, hookId) {
    try {
        const result = await api(`/hooks/optional/snippet?hook_name=${encodeURIComponent(hookName)}`);
        const snippetEl = document.getElementById(`snippet-${hookId}`);
        if (snippetEl && result.success) {
            // Use <pre> inside .code-block (matching existing pattern)
            snippetEl.innerHTML = `<pre>${escapeHtml(result.snippet)}</pre>`;
        }
    } catch (err) {
        console.error('Error loading snippet:', err);
    }
}

/**
 * Install optional hook (file only)
 */
async function installOptionalHook(hookName) {
    const btn = event.target;
    btn.disabled = true;
    btn.textContent = 'Installing...';

    try {
        const result = await api('/hooks/optional/install', {
            method: 'POST',
            body: { hook_name: hookName }
        });

        if (result.success) {
            await loadOptionalHooks();
        } else {
            btn.textContent = 'Error';
            setTimeout(() => loadOptionalHooks(), 2000);
        }
    } catch (err) {
        console.error('Error installing hook:', err);
        btn.textContent = 'Error';
        setTimeout(() => loadOptionalHooks(), 2000);
    }
}

/**
 * Wire optional hook to settings.json
 */
async function wireOptionalHook(hookName) {
    const btn = event.target;
    btn.disabled = true;
    btn.textContent = 'Wiring...';

    try {
        const result = await api('/hooks/optional/wire', {
            method: 'POST',
            body: { hook_name: hookName }
        });

        if (result.success) {
            await loadOptionalHooks();
            await loadSessions();
        } else {
            btn.textContent = 'Error';
            setTimeout(() => loadOptionalHooks(), 2000);
        }
    } catch (err) {
        console.error('Error wiring hook:', err);
        btn.textContent = 'Error';
        setTimeout(() => loadOptionalHooks(), 2000);
    }
}

/**
 * Copy hook snippet to clipboard
 */
async function copyHookSnippet(hookName) {
    try {
        const result = await api(`/hooks/optional/snippet?hook_name=${encodeURIComponent(hookName)}`);
        if (result.success) {
            await navigator.clipboard.writeText(result.snippet);
            const btn = event.target;
            const originalText = btn.textContent;
            btn.textContent = 'Copied!';
            setTimeout(() => btn.textContent = originalText, 2000);
        }
    } catch (err) {
        console.error('Error copying snippet:', err);
    }
}

/**
 * Toggle optional hook global enabled state
 */
async function toggleOptionalHook(hookName, enabled) {
    try {
        const result = await api('/hooks/optional/toggle', {
            method: 'POST',
            body: { hook_name: hookName, enabled: enabled }
        });

        if (result.success) {
            // Sync all checkboxes for this hook (in both Addons tab and Settings tab)
            document.querySelectorAll(`[data-hook="${hookName}"] input[type="checkbox"]`).forEach(checkbox => {
                checkbox.checked = enabled;
            });
            document.querySelectorAll(`input[data-hook="${hookName}"]`).forEach(checkbox => {
                checkbox.checked = enabled;
            });
        } else {
            // Revert on failure
            await loadOptionalHooks();
        }
    } catch (err) {
        console.error('Error toggling hook:', err);
        await loadOptionalHooks();
    }
}

/**
 * Uninstall optional hook
 */
async function uninstallOptionalHook(hookName) {
    const btn = event.target;
    btn.disabled = true;
    btn.textContent = 'Uninstalling...';

    try {
        const result = await api('/hooks/optional/uninstall', {
            method: 'POST',
            body: { hook_name: hookName }
        });

        if (result.success) {
            await loadOptionalHooks();
            await loadSessions();
        } else {
            btn.textContent = 'Error';
            setTimeout(() => loadOptionalHooks(), 2000);
        }
    } catch (err) {
        console.error('Error uninstalling hook:', err);
        btn.textContent = 'Error';
        setTimeout(() => loadOptionalHooks(), 2000);
    }
}

/**
 * Update Settings page addon section
 * Uses existing toggle-item and switch patterns from Core Settings
 */
function updateSettingsAddonSection(hooks) {
    const wiredHooks = hooks.filter(h => h.status === 'wired');
    const addonSection = document.getElementById('installed-addons-settings');

    if (!addonSection) return;

    if (wiredHooks.length === 0) {
        addonSection.style.display = 'none';
        return;
    }

    addonSection.style.display = 'block';
    const listEl = document.getElementById('addon-toggles-list');
    if (!listEl) return;

    // Use toggle-item pattern (same as Core Settings toggles)
    listEl.innerHTML = wiredHooks.map(hook => `
        <div class="toggle-item" data-hook="${hook.filename}">
            <div class="toggle-info">
                <label>${hook.name}</label>
                <span class="toggle-description">Hook: ${hook.hook_type}</span>
            </div>
            <label class="switch">
                <input type="checkbox" ${hook.global_enabled ? 'checked' : ''}
                       data-hook="${hook.filename}"
                       onchange="toggleOptionalHook('${hook.filename}', this.checked)">
                <span class="slider"></span>
            </label>
        </div>
    `).join('');
}

/**
 * Escape HTML for safe display
 */
function escapeHtml(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
}

// Legacy handler for backwards compatibility
async function handleOptionalHook(hookName, action) {
    if (action === 'install') {
        await installOptionalHook(hookName);
    } else {
        await uninstallOptionalHook(hookName);
    }
}

// ---- Sessions Functions ----

const sessionsListEl = document.getElementById('sessions-list');
const noSessionsEl = document.getElementById('no-sessions');

// Available toggles (loaded dynamically)
let availableToggles = [];

/**
 * Load available toggles for session overrides
 */
async function loadAvailableToggles() {
    try {
        const result = await api('/available-toggles');
        if (result.success && result.toggles) {
            availableToggles = result.toggles;
        }
    } catch (err) {
        console.error('Error loading available toggles:', err);
    }
}

/**
 * Load and render active sessions
 */
async function loadSessions() {
    if (!isConnected) return;

    sessionsListEl.innerHTML = '<div class="loading">Loading sessions...</div>';
    noSessionsEl.style.display = 'none';

    // First load available toggles
    await loadAvailableToggles();

    try {
        const result = await api('/sessions');

        if (!result.success) {
            sessionsListEl.innerHTML = `<div class="error">${result.error}</div>`;
            return;
        }

        const sessions = result.sessions || [];

        if (sessions.length === 0) {
            sessionsListEl.innerHTML = '';
            noSessionsEl.style.display = 'block';
            return;
        }

        sessionsListEl.innerHTML = '';
        sessions.forEach(session => {
            sessionsListEl.appendChild(renderSession(session));
        });
    } catch (err) {
        console.error('Error loading sessions:', err);
        sessionsListEl.innerHTML = '<div class="error">Error loading sessions</div>';
    }
}

/**
 * Render a single session card
 */
function renderSession(session) {
    const div = document.createElement('div');
    div.className = 'session-item';
    div.dataset.uuid = session.uuid;

    // Format times
    const started = new Date(session.started);
    const lastActivity = session.last_activity ? new Date(session.last_activity) : null;
    const timeStr = started.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
    const dateStr = started.toLocaleDateString([], { month: 'short', day: 'numeric' });
    const fullStarted = started.toLocaleString();
    const fullLastActivity = lastActivity ? lastActivity.toLocaleString() : 'N/A';

    // Short UUID for collapsed header
    const shortUuid = session.uuid.substring(0, 8) + '...';

    // Truncate cwd for overview
    const cwd = session.cwd || 'Unknown';
    const truncatedCwd = cwd.length > 40 ? '...' + cwd.slice(-37) : cwd;

    // Get active domain names (only _STATE keys that are effectively true)
    // Use effective values (merged with global) if available, otherwise fall back to overrides
    const effective = session.effective || session.overrides || {};
    const activeDomains = Object.entries(effective)
        .filter(([key, value]) => key.endsWith('_STATE') && value === true)
        .map(([key]) => key.replace('_STATE', ''));
    const activeCount = activeDomains.length;

    // Create truncated domain list for display (show first 3, then "+N more")
    const fullDomainList = activeDomains.join(', ') || 'None';
    let truncatedDomains;
    if (activeDomains.length === 0) {
        truncatedDomains = 'None enabled';
    } else if (activeDomains.length <= 3) {
        truncatedDomains = activeDomains.join(', ');
    } else {
        truncatedDomains = activeDomains.slice(0, 3).join(', ') + ` +${activeDomains.length - 3} more`;
    }

    // Session title (editable) - falls back to label if no title
    const displayTitle = session.title || session.label || 'Untitled Session';

    // Initialize lastSavedTitle to prevent spurious saves on first blur
    lastSavedTitle[session.uuid] = session.title || '';

    div.innerHTML = `
        <div class="session-header" onclick="toggleSessionExpand('${session.uuid}')">
            <div class="session-info">
                <span class="session-label">${displayTitle}</span>
                <span class="session-time">${dateStr} ${timeStr}</span>
                <span class="session-domains-preview" title="${fullDomainList}">${truncatedDomains}</span>
            </div>
            <span class="session-uuid" title="${session.uuid}">${shortUuid}</span>
            <span class="expand-icon">▶</span>
        </div>
        <div class="session-details" style="display: none;">
            <div class="session-meta">
                <div class="meta-row">
                    <span class="meta-label">Title:</span>
                    <span class="meta-value session-title-edit">
                        <input type="text" class="session-title-input" value="${session.title || ''}"
                               placeholder="Enter session title..."
                               data-uuid="${session.uuid}"
                               onclick="event.stopPropagation()"
                               onkeydown="if(event.key==='Enter'){saveSessionTitle('${session.uuid}', this.value, event)}"
                               onblur="saveSessionTitle('${session.uuid}', this.value, event)">
                    </span>
                </div>
                <div class="meta-row">
                    <span class="meta-label">Session ID:</span>
                    <span class="meta-value session-id-full" title="Click to copy">
                        <code>${session.uuid}</code>
                        <button class="copy-btn" onclick="copySessionId('${session.uuid}', event)" title="Copy to clipboard">📋</button>
                    </span>
                </div>
                <div class="meta-row">
                    <span class="meta-label">Config File:</span>
                    <span class="meta-value filepath truncated" title="${session.filepath || 'N/A'}">
                        <code>${session.filepath ? truncatePath(session.filepath, 50) : 'N/A'}</code>
                        ${session.filepath ? `<button class="copy-btn" onclick="copyToClipboard('${session.filepath.replace(/\\/g, '\\\\')}', event)" title="Copy path">📋</button>` : ''}
                    </span>
                </div>
                <div class="meta-row">
                    <span class="meta-label">Working Dir:</span>
                    <span class="meta-value truncated" title="${cwd}">${truncatedCwd}</span>
                </div>
                <div class="meta-row">
                    <span class="meta-label">Started:</span>
                    <span class="meta-value">${fullStarted}</span>
                </div>
                <div class="meta-row">
                    <span class="meta-label">Last Activity:</span>
                    <span class="meta-value">${fullLastActivity}</span>
                </div>
            </div>
            <div class="session-overrides-section">
                <div class="overrides-header">Domain Toggles</div>
                ${renderSessionOverrides(session)}
            </div>
        </div>
    `;

    return div;
}

/**
 * Copy session ID to clipboard
 */
function copySessionId(uuid, event) {
    event.stopPropagation();
    navigator.clipboard.writeText(uuid).then(() => {
        showToast('Session ID copied to clipboard', 'success');
    }).catch(err => {
        console.error('Failed to copy:', err);
        showToast('Failed to copy to clipboard', 'error');
    });
}

/**
 * Copy any text to clipboard
 */
function copyToClipboard(text, event) {
    event.stopPropagation();
    navigator.clipboard.writeText(text).then(() => {
        showToast('Copied to clipboard', 'success');
    }).catch(err => {
        console.error('Failed to copy:', err);
        showToast('Failed to copy to clipboard', 'error');
    });
}

/**
 * Save session title
 */
let lastSavedTitle = {};  // Track last saved value to avoid duplicate saves
async function saveSessionTitle(uuid, title, event) {
    event.stopPropagation();

    // Skip if unchanged
    if (lastSavedTitle[uuid] === title) return;
    lastSavedTitle[uuid] = title;

    try {
        const result = await api(`/sessions/${uuid}/title`, {
            method: 'PUT',
            body: { title }
        });

        if (result.success) {
            // Update the header label only if title has a value
            // If empty, keep the existing label (which shows session.label or 'Untitled Session')
            if (title) {
                const sessionEl = document.querySelector(`.session-item[data-uuid="${uuid}"]`);
                if (sessionEl) {
                    const labelEl = sessionEl.querySelector('.session-label');
                    if (labelEl) {
                        labelEl.textContent = title;
                    }
                }
            }
            showToast('Title saved', 'success');
        } else {
            showToast('Error saving title: ' + (result.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        showToast('Error saving title', 'error');
    }
}

/**
 * Truncate a file path for display
 */
function truncatePath(path, maxLen) {
    if (path.length <= maxLen) return path;
    return '...' + path.slice(-(maxLen - 3));
}

/**
 * Render session override toggles (2-state: On | Off)
 * New domains default to Off until manually enabled
 * Separates domain toggles from addon toggles
 */
function renderSessionOverrides(session) {
    const overrides = session.overrides || {};
    const effective = session.effective || {};

    // Use dynamically loaded toggles, or fall back to basic ones
    const allToggles = availableToggles.length > 0 ? availableToggles : [
        { key: 'DEVMODE', label: 'DEVMODE' },
        { key: 'GLOBAL_STATE', label: 'GLOBAL' },
        { key: 'DEVELOPMENT_STATE', label: 'DEVELOPMENT' }
    ];

    // Separate domain toggles from addon toggles
    const domainToggles = allToggles.filter(t => t.type !== 'addon');
    const addonToggles = allToggles.filter(t => t.type === 'addon');

    // Helper to render a single toggle row
    const renderToggleRow = ({ key, label, description, recall, exclude, hook_type }) => {
        // Check if there's an explicit override, otherwise use effective (inherited) value
        const hasOverride = overrides[key] !== null && overrides[key] !== undefined;
        const currentValue = hasOverride ? overrides[key] === true : effective[key] === true;

        // Helper to format comma-separated lists with proper spacing
        const formatList = (text) => {
            if (!text) return '';
            return text.replace(/,(?!\s)/g, ', ').trim();
        };

        // Build trigger words line (only if recall keywords exist)
        let triggerText = '';
        let triggerFull = '';
        if (recall) {
            triggerFull = formatList(recall);
            triggerText = triggerFull.length > 50 ? triggerFull.substring(0, 47) + '...' : triggerFull;
        }

        // Build description line (for items without recall keywords, like DevMode)
        let descText = '';
        let descFull = '';
        if (!recall && description && !description.startsWith('Enable ')) {
            descFull = description;
            descText = description.length > 55 ? description.substring(0, 52) + '...' : description;
        }

        // Build excluded line
        let excludeText = '';
        let excludeFull = '';
        if (exclude) {
            excludeFull = formatList(exclude);
            excludeText = excludeFull.length > 50 ? excludeFull.substring(0, 47) + '...' : excludeFull;
        }

        // For addon toggles, show hook type instead of triggers
        let hookTypeHtml = '';
        if (hook_type) {
            hookTypeHtml = `<span class="override-meta desc">Hook: <code>${hook_type}</code></span>`;
        }

        return `
            <div class="override-row" data-key="${key}">
                <div class="override-info">
                    <span class="override-label">${label}</span>
                    ${triggerText ? `<span class="override-meta trigger" title="${triggerFull}"><span class="meta-prefix">Triggers:</span> ${triggerText}</span>` : ''}
                    ${descText ? `<span class="override-meta desc" title="${descFull}">${descText}</span>` : ''}
                    ${hookTypeHtml}
                    ${excludeText ? `<span class="override-meta exclude" title="${excludeFull}"><span class="meta-prefix">Excluded:</span> ${excludeText}</span>` : ''}
                </div>
                <div class="override-toggle">
                    <label class="switch">
                        <input type="checkbox"
                               ${currentValue ? 'checked' : ''}
                               onchange="handleSessionOverrideChange('${session.uuid}', '${key}', this.checked)">
                        <span class="slider"></span>
                    </label>
                </div>
            </div>
        `;
    };

    // Render domain toggles
    let html = domainToggles.map(renderToggleRow).join('');

    // Render addon toggles section if any exist
    if (addonToggles.length > 0) {
        html += `
            <div class="overrides-header" style="margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border-subtle);">Addon Toggles</div>
        `;
        html += addonToggles.map(renderToggleRow).join('');
    }

    return html;
}

/**
 * Toggle session expansion
 */
function toggleSessionExpand(uuid) {
    const sessionEl = document.querySelector(`.session-item[data-uuid="${uuid}"]`);
    if (!sessionEl) return;

    const detailsEl = sessionEl.querySelector('.session-details');
    const expandIcon = sessionEl.querySelector('.expand-icon');

    if (detailsEl.style.display === 'none') {
        detailsEl.style.display = 'block';
        expandIcon.textContent = '▼';
        sessionEl.classList.add('expanded');
    } else {
        detailsEl.style.display = 'none';
        expandIcon.textContent = '▶';
        sessionEl.classList.remove('expanded');
    }
}

/**
 * Handle session override change - instant UI, async backend
 */
async function handleSessionOverrideChange(uuid, key, value) {
    // UI is already updated via checkbox change - no refresh needed
    // Just sync to backend asynchronously
    try {
        const overrides = { [key]: value };
        const result = await api(`/sessions/${uuid}`, {
            method: 'PUT',
            body: { overrides }
        });

        if (!result.success) {
            // Revert UI on error
            const checkbox = document.querySelector(`.session-item[data-uuid="${uuid}"] .override-row[data-key="${key}"] input[type="checkbox"]`);
            if (checkbox) {
                checkbox.checked = !value;  // Revert
            }
            showToast('Error saving toggle: ' + (result.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        console.error('Error updating session override:', err);
    }
}

// ---- Domain Management Functions ----

const domainsListEl = document.getElementById('domains-list');
const mainNavEl = document.getElementById('main-nav');
const domainsView = document.getElementById('domains-view');
let pendingDeleteDomain = null;
let allDomains = []; // Store all domains for filtering

/**
 * Initialize main navigation tabs
 */
function initMainNav() {
    document.querySelectorAll('.nav-tab').forEach(btn => {
        btn.addEventListener('click', handleMainNavSwitch);
    });

    // Create domain button
    const createDomainBtn = document.getElementById('btn-create-domain');
    if (createDomainBtn) {
        createDomainBtn.addEventListener('click', openCreateDomainModal);
    }

    // Import domains button
    const importDomainsBtn = document.getElementById('btn-import-domains');
    if (importDomainsBtn) {
        importDomainsBtn.addEventListener('click', openImportDomainsModal);
    }

    // Auto-uppercase domain name input
    const domainNameInput = document.getElementById('domain-name');
    if (domainNameInput) {
        domainNameInput.addEventListener('input', (e) => {
            e.target.value = e.target.value.toUpperCase().replace(/[^A-Z_]/g, '');
        });
    }
}

/**
 * Handle main navigation tab switching
 */
function handleMainNavSwitch(event) {
    const viewName = event.target.dataset.view;

    // Update active nav tab
    document.querySelectorAll('.nav-tab').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.view === viewName);
    });

    // Update active view
    settingsView.classList.toggle('active', viewName === 'settings');
    if (domainsView) {
        domainsView.classList.toggle('active', viewName === 'domains');
    }
    if (addonsView) {
        addonsView.classList.toggle('active', viewName === 'addons');
    }

    // Load data when switching views
    if (viewName === 'domains') {
        loadDomains();
    } else if (viewName === 'addons') {
        loadAddons();
        loadOptionalHooks();
    }
}

/**
 * Show main navigation (called when connected)
 */
function showMainNav() {
    if (mainNavEl) {
        mainNavEl.style.display = 'flex';
    }
}

/**
 * Hide main navigation (called when disconnected)
 */
function hideMainNav() {
    if (mainNavEl) {
        mainNavEl.style.display = 'none';
    }
}

/**
 * Load and render domains list
 */
async function loadDomains() {
    if (!isConnected) return;

    domainsListEl.innerHTML = '<div class="loading">Loading domains...</div>';

    try {
        const result = await api('/domains');

        if (result.error) {
            domainsListEl.innerHTML = `<div class="error">${result.error}</div>`;
            return;
        }

        allDomains = result.domains || [];

        // Clear search when reloading
        const searchInput = document.getElementById('domain-search-input');
        if (searchInput) searchInput.value = '';

        renderFilteredDomains(allDomains);
    } catch (err) {
        console.error('Error loading domains:', err);
        domainsListEl.innerHTML = `<div class="error">Error: ${err.message}</div>`;
    }
}

// Core CARL domains (special handling, no recall keywords)
const CORE_DOMAINS = ['GLOBAL', 'CONTEXT', 'COMMANDS'];

/**
 * Check if domain is a core CARL domain
 */
function isCoreDomain(name) {
    return CORE_DOMAINS.includes(name.toUpperCase());
}

/**
 * Get description for core domain trigger mechanism
 */
function getCoreDescription(name) {
    switch (name.toUpperCase()) {
        case 'GLOBAL': return 'Always injected';
        case 'CONTEXT': return 'Context % based';
        case 'COMMANDS': return '*star syntax';
        default: return '';
    }
}

/**
 * Render filtered domains list
 */
function renderFilteredDomains(domains) {
    if (domains.length === 0) {
        domainsListEl.innerHTML = '<div class="no-domains">No domains found</div>';
        return;
    }

    domainsListEl.innerHTML = '';

    // Separate core and regular domains
    const coreDomains = domains.filter(d => isCoreDomain(d.name));
    const regularDomains = domains.filter(d => !isCoreDomain(d.name));

    // Render Core CARL Domains section (if any)
    if (coreDomains.length > 0) {
        const coreSection = document.createElement('div');
        coreSection.className = 'domains-section core-domains-section';
        coreSection.innerHTML = `
            <div class="section-label">Core CARL Domains</div>
        `;
        coreDomains.forEach((domain, idx) => {
            const globalIndex = allDomains.findIndex(d => d.name === domain.name);
            // Pass section-relative index for reorder button state
            coreSection.appendChild(renderDomainCard(domain, globalIndex, allDomains.length, idx, coreDomains.length));
        });
        domainsListEl.appendChild(coreSection);
    }

    // Render Regular Domains section (if any)
    if (regularDomains.length > 0) {
        const regularSection = document.createElement('div');
        regularSection.className = 'domains-section regular-domains-section';
        if (coreDomains.length > 0) {
            regularSection.innerHTML = `
                <div class="section-label">Custom Domains</div>
            `;
        }
        regularDomains.forEach((domain, idx) => {
            const globalIndex = allDomains.findIndex(d => d.name === domain.name);
            // Pass section-relative index for reorder button state
            regularSection.appendChild(renderDomainCard(domain, globalIndex, allDomains.length, idx, regularDomains.length));
        });
        domainsListEl.appendChild(regularSection);
    }
}

/**
 * Filter domains by search query
 */
function filterDomains() {
    const searchInput = document.getElementById('domain-search-input');
    const query = (searchInput?.value || '').toLowerCase().trim();

    if (!query) {
        renderFilteredDomains(allDomains);
        return;
    }

    const filtered = allDomains.filter(domain => {
        // Search in name
        if (domain.name.toLowerCase().includes(query)) return true;
        // Search in recall keywords
        const keywords = domain.recall_keywords || [];
        if (keywords.some(kw => kw.toLowerCase().includes(query))) return true;
        return false;
    });

    if (filtered.length === 0) {
        domainsListEl.innerHTML = `<div class="no-domains">No domains matching "${query}"</div>`;
    } else {
        renderFilteredDomains(filtered);
    }
}

/**
 * Render a single domain card
 * @param {object} domain - Domain data
 * @param {number} index - Global index in allDomains (for moveDomain)
 * @param {number} total - Total domains count
 * @param {number} sectionIndex - Index within current section (for reorder buttons)
 * @param {number} sectionTotal - Total in current section (for reorder buttons)
 */
function renderDomainCard(domain, index, total, sectionIndex = index, sectionTotal = total) {
    const div = document.createElement('div');
    div.className = `domain-card ${domain.state ? 'active' : 'inactive'}`;
    div.dataset.name = domain.name;

    // Check if core domain
    const isCore = isCoreDomain(domain.name);

    // Format recall keywords for display (show first 3) - only for non-core domains
    const keywords = domain.recall_keywords || [];
    const keywordsDisplay = keywords.slice(0, 3).join(', ');
    const moreCount = keywords.length > 3 ? ` +${keywords.length - 3} more` : '';

    // Determine badges - core domains get single "CARL" badge
    const badges = [];
    if (isCore) {
        badges.push('<span class="domain-badge carl">CARL</span>');
    }

    // Determine state button
    const stateClass = domain.state ? 'state-active' : 'state-inactive';
    const stateText = domain.state ? 'Active' : 'Inactive';

    // Delete button (disabled for protected domains)
    const deleteDisabled = domain.is_protected ? 'disabled' : '';
    const deleteTitle = domain.is_protected ? 'Cannot delete protected domain' : 'Delete domain';

    // Reorder buttons - use section-relative index to respect section boundaries
    const isFirst = sectionIndex === 0;
    const isLast = sectionIndex === sectionTotal - 1;

    div.innerHTML = `
        <div class="domain-card-wrapper">
            <div class="domain-reorder">
                <button class="reorder-btn" onclick="moveDomain('${domain.name}', 'up')" title="Move up" ${isFirst ? 'disabled' : ''}>▲</button>
                <button class="reorder-btn" onclick="moveDomain('${domain.name}', 'down')" title="Move down" ${isLast ? 'disabled' : ''}>▼</button>
            </div>
            <div class="domain-content">
                <div class="domain-header">
                    <div class="domain-name-row">
                        <span class="domain-name">${domain.name}</span>
                        ${badges.join('')}
                    </div>
                    <button class="btn btn-small state-toggle ${stateClass}"
                            onclick="toggleDomainState('${domain.name}')"
                            ${domain.always_on && domain.name !== 'GLOBAL' ? 'disabled title="Always-on domains cannot be toggled"' : ''}>
                        ${stateText}
                    </button>
                </div>
                <div class="domain-info">
                    <div class="domain-stat">
                        ${domain.name === 'COMMANDS' ? `
                        <span class="stat-label">Commands:</span>
                        <span class="stat-value">${domain.command_count || 0}</span>
                        <span class="stat-label" style="margin-left: 12px;">Rules:</span>
                        <span class="stat-value">${domain.rule_count || 0}</span>
                        ` : `
                        <span class="stat-label">Rules:</span>
                        <span class="stat-value">${domain.rule_count || 0}</span>
                        `}
                    </div>
                    ${isCore ? `
                    <div class="domain-trigger">
                        <span class="stat-label">Trigger:</span>
                        <span class="stat-value core-trigger">${getCoreDescription(domain.name)}</span>
                    </div>
                    ` : `
                    <div class="domain-keywords" title="${keywords.join(', ')}">
                        <span class="stat-label">Recall:</span>
                        <span class="stat-value">${keywordsDisplay}${moreCount}</span>
                    </div>
                    `}
                </div>
                <div class="domain-actions">
                    <button class="btn btn-small btn-secondary" onclick="viewDomainDetail('${domain.name}')">
                        View Rules
                    </button>
                    <button class="btn btn-small btn-danger" onclick="deleteDomain('${domain.name}')"
                            ${deleteDisabled} title="${deleteTitle}">
                        Delete
                    </button>
                </div>
            </div>
        </div>
    `;

    return div;
}

/**
 * Move domain up or down in the list
 */
async function moveDomain(name, direction) {
    const index = allDomains.findIndex(d => d.name === name);
    if (index === -1) return;

    const newIndex = direction === 'up' ? index - 1 : index + 1;

    // Validate bounds
    if (newIndex < 0 || newIndex >= allDomains.length) return;

    // Swap in local array first (optimistic update)
    [allDomains[index], allDomains[newIndex]] = [allDomains[newIndex], allDomains[index]];

    // Re-render immediately without refresh
    renderFilteredDomains(allDomains);

    // Build order for API
    const order = allDomains.map(d => d.name);

    try {
        const result = await api('/domains/reorder', {
            method: 'POST',
            body: { order: order }
        });

        if (!result.success) {
            // Revert on failure
            [allDomains[index], allDomains[newIndex]] = [allDomains[newIndex], allDomains[index]];
            renderFilteredDomains(allDomains);
            showToast(result.error || 'Failed to reorder domains', 'error');
        }
    } catch (err) {
        // Revert on error
        [allDomains[index], allDomains[newIndex]] = [allDomains[newIndex], allDomains[index]];
        renderFilteredDomains(allDomains);
        console.error('Error reordering domains:', err);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Toggle domain state (active/inactive)
 */
async function toggleDomainState(name) {
    // Find domain in local array
    const domain = allDomains.find(d => d.name === name);
    if (!domain) return;

    const oldState = domain.state;
    const newState = !oldState;

    // Optimistic UI update
    domain.state = newState;
    updateDomainCardState(name, newState);

    try {
        const result = await api(`/domains/${name}`, {
            method: 'PUT',
            body: { state: newState }
        });

        if (!result.success) {
            // Revert on failure
            domain.state = oldState;
            updateDomainCardState(name, oldState);
            showToast(result.error || 'Failed to update domain state', 'error');
        }
    } catch (err) {
        // Revert on error
        domain.state = oldState;
        updateDomainCardState(name, oldState);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Update domain card state in the UI without full reload
 */
function updateDomainCardState(name, newState) {
    const card = document.querySelector(`.domain-card[data-name="${name}"]`);
    if (!card) return;

    // Update card class
    card.classList.toggle('active', newState);
    card.classList.toggle('inactive', !newState);

    // Update button
    const btn = card.querySelector('.state-toggle');
    if (btn) {
        btn.classList.toggle('state-active', newState);
        btn.classList.toggle('state-inactive', !newState);
        btn.textContent = newState ? 'Active' : 'Inactive';
    }
}

// ---- Import Domains Functions ----

let importSourcePath = null;
let importSourceDomains = [];
let currentWorkspaceDomains = [];

function openImportDomainsModal() {
    importSourcePath = null;
    importSourceDomains = [];
    document.getElementById('import-source-path').textContent = 'No source selected';
    document.getElementById('import-domains-section').style.display = 'none';
    document.getElementById('import-domains-list').innerHTML = '';
    document.getElementById('import-conflicts-warning').style.display = 'none';
    document.getElementById('btn-confirm-import').disabled = true;
    document.getElementById('import-domains-modal').style.display = 'flex';

    // Store current domains for conflict detection
    currentWorkspaceDomains = allDomains.map(d => d.name);
}

function closeImportDomainsModal() {
    document.getElementById('import-domains-modal').style.display = 'none';
    importSourcePath = null;
    importSourceDomains = [];
}

function clearImportSource() {
    importSourcePath = null;
    importSourceDomains = [];
    document.getElementById('import-source-path').textContent = 'No source selected';
    document.getElementById('import-domains-section').style.display = 'none';
    document.getElementById('import-domains-list').innerHTML = '';
    document.getElementById('import-conflicts-warning').style.display = 'none';
    document.getElementById('btn-confirm-import').disabled = true;
    document.getElementById('btn-clear-import-source').style.display = 'none';
}

async function browseImportSource() {
    try {
        const result = await api('/browse-folder', { method: 'POST' });
        if (!result.path) return; // User cancelled

        // Validate it's a .carl folder or contains one
        const checkResult = await api('/domains/import/check', {
            method: 'POST',
            body: { path: result.path }
        });

        if (!checkResult.success) {
            showToast(checkResult.error || 'Invalid source folder', 'error');
            return;
        }

        importSourcePath = checkResult.carl_path;
        importSourceDomains = checkResult.domains || [];

        document.getElementById('import-source-path').textContent = importSourcePath;
        document.getElementById('btn-clear-import-source').style.display = 'inline-block';
        renderImportDomainsList();
        document.getElementById('import-domains-section').style.display = 'block';

    } catch (err) {
        console.error('Error browsing for import source:', err);
        showToast('Error: ' + err.message, 'error');
    }
}

function renderImportDomainsList() {
    const listEl = document.getElementById('import-domains-list');
    const warningEl = document.getElementById('import-conflicts-warning');
    const confirmBtn = document.getElementById('btn-confirm-import');

    if (importSourceDomains.length === 0) {
        listEl.innerHTML = '<div class="no-items">No domains found in source</div>';
        confirmBtn.disabled = true;
        return;
    }

    // Sort domains: GLOBAL, COMMANDS, CONTEXT first, then others alphabetically
    const specialOrder = ['GLOBAL', 'COMMANDS', 'CONTEXT'];
    const sortedDomains = [...importSourceDomains].sort((a, b) => {
        const aUpper = a.name.toUpperCase();
        const bUpper = b.name.toUpperCase();
        const aIdx = specialOrder.indexOf(aUpper);
        const bIdx = specialOrder.indexOf(bUpper);

        if (aIdx !== -1 && bIdx !== -1) return aIdx - bIdx;  // Both special - use order
        if (aIdx !== -1) return -1;  // a is special, comes first
        if (bIdx !== -1) return 1;   // b is special, comes first
        return aUpper.localeCompare(bUpper);  // Both regular - alphabetical
    });

    let hasConflicts = false;
    let html = '';

    for (const domain of sortedDomains) {
        const isConflict = currentWorkspaceDomains.includes(domain.name);
        if (isConflict) hasConflicts = true;

        const rules = domain.rules || [];
        const ruleCount = domain.rule_count || rules.length;
        const isSpecial = domain.is_special || false;
        const specialType = domain.special_type || '';

        // Build rules/info badge based on domain type
        let infoBadgeHtml = '';
        let infoTooltipHtml = '';

        if (specialType === 'commands') {
            // COMMANDS domain - show pill per command with rules tooltip
            const commands = domain.commands || {};
            const cmdPills = Object.entries(commands).map(([cmd, data]) => {
                const cmdRules = data.rules || [];
                const count = data.count || cmdRules.length;
                if (count === 0) return '';

                const ruleTexts = cmdRules.slice(0, 5).map((r, i) => {
                    const truncated = r.length > 100 ? r.substring(0, 100) + '...' : r;
                    return `<div class="tooltip-rule"><span class="tooltip-rule-num">${i + 1}</span>${escapeHtml(truncated)}</div>`;
                }).join('');
                const moreText = count > 5 ? `<div class="tooltip-more">+${count - 5} more...</div>` : '';

                return `
                    <span class="rules-tooltip-trigger" onmouseenter="positionTooltip(event)" onclick="event.preventDefault()">
                        <span class="checkbox-meta cmd-pill">*${cmd.toLowerCase()}</span>
                        <div class="rules-tooltip">${ruleTexts}${moreText}</div>
                    </span>`;
            }).filter(p => p).join('');

            infoBadgeHtml = cmdPills || '<span class="checkbox-meta">0 commands</span>';
            infoTooltipHtml = `<span class="special-badge">*star syntax</span>`;

        } else if (specialType === 'context') {
            // CONTEXT domain - show pill per bracket with rules tooltip
            const brackets = domain.brackets || {};
            const bracketPills = ['FRESH', 'MODERATE', 'DEPLETED'].map(b => {
                const data = brackets[b] || {count: 0, rules: []};
                const bracketRules = data.rules || [];
                const count = data.count || bracketRules.length;

                const ruleTexts = bracketRules.slice(0, 5).map((r, i) => {
                    const truncated = r.length > 100 ? r.substring(0, 100) + '...' : r;
                    return `<div class="tooltip-rule"><span class="tooltip-rule-num">${i + 1}</span>${escapeHtml(truncated)}</div>`;
                }).join('');
                const moreText = count > 5 ? `<div class="tooltip-more">+${count - 5} more...</div>` : '';
                const emptyText = count === 0 ? '<div class="text-muted">No rules</div>' : '';

                return `
                    <span class="rules-tooltip-trigger" onmouseenter="positionTooltip(event)" onclick="event.preventDefault()">
                        <span class="checkbox-meta bracket-pill ${count === 0 ? 'empty' : ''}">${b} (${count})</span>
                        <div class="rules-tooltip">${ruleTexts}${moreText}${emptyText}</div>
                    </span>`;
            }).join('');

            infoBadgeHtml = bracketPills;
            infoTooltipHtml = `<span class="special-badge">% brackets</span>`;

        } else if (specialType === 'global') {
            // GLOBAL domain - always injected, no recall
            if (ruleCount > 0) {
                const ruleTexts = rules.slice(0, 7).map((r, i) => {
                    const text = typeof r === 'string' ? r : r.text || '';
                    const truncated = text.length > 140 ? text.substring(0, 140) + '...' : text;
                    return `<div class="tooltip-rule"><span class="tooltip-rule-num">${i + 1}</span>${escapeHtml(truncated)}</div>`;
                }).join('');
                const moreText = ruleCount > 7 ? `<div class="tooltip-more">+${ruleCount - 7} more...</div>` : '';
                infoBadgeHtml = `
                    <span class="rules-tooltip-trigger" onmouseenter="positionTooltip(event)" onclick="event.preventDefault()">
                        <span class="checkbox-meta">${ruleCount} rule${ruleCount !== 1 ? 's' : ''}</span>
                        <div class="rules-tooltip">${ruleTexts}${moreText}</div>
                    </span>`;
            } else {
                infoBadgeHtml = `<span class="checkbox-meta">0 rules</span>`;
            }
            infoTooltipHtml = `<span class="special-badge">always injects</span>`;

        } else {
            // Standard domain - rules badge with tooltip
            if (ruleCount > 0) {
                const ruleTexts = rules.slice(0, 7).map((r, i) => {
                    const text = typeof r === 'string' ? r : r.text || '';
                    const truncated = text.length > 140 ? text.substring(0, 140) + '...' : text;
                    return `<div class="tooltip-rule"><span class="tooltip-rule-num">${i + 1}</span>${escapeHtml(truncated)}</div>`;
                }).join('');
                const moreText = ruleCount > 7 ? `<div class="tooltip-more">+${ruleCount - 7} more...</div>` : '';
                infoBadgeHtml = `
                    <span class="rules-tooltip-trigger" onmouseenter="positionTooltip(event)" onclick="event.preventDefault()">
                        <span class="checkbox-meta">${ruleCount} rule${ruleCount !== 1 ? 's' : ''}</span>
                        <div class="rules-tooltip">${ruleTexts}${moreText}</div>
                    </span>`;
            } else {
                infoBadgeHtml = `<span class="checkbox-meta">0 rules</span>`;
            }

            // Recall keywords tooltip for standard domains
            const recallStr = domain.recall || '';
            if (recallStr) {
                const keywords = recallStr.split(',').map(k => k.trim()).filter(k => k);
                const keywordHtml = keywords.map(k => `<div class="tooltip-keyword">${escapeHtml(k)}</div>`).join('');
                infoTooltipHtml = `
                    <span class="rules-tooltip-trigger" onmouseenter="positionTooltip(event)" onclick="event.preventDefault()">
                        <span class="checkbox-meta recall-pill">${keywords.length} keyword${keywords.length !== 1 ? 's' : ''}</span>
                        <div class="rules-tooltip recall-tooltip">${keywordHtml}</div>
                    </span>`;
            }
        }

        html += `
            <label class="checkbox-item ${isConflict ? 'has-conflict' : ''} ${isSpecial ? 'is-core' : ''}">
                <input type="checkbox" value="${domain.name}" checked>
                <span class="checkbox-label">
                    <strong>${domain.name.toUpperCase()}</strong>
                    ${infoBadgeHtml}
                    ${infoTooltipHtml}
                    ${isConflict ? '<span class="conflict-badge">Exists</span>' : ''}
                </span>
            </label>
        `;
    }

    listEl.innerHTML = html;
    warningEl.style.display = hasConflicts ? 'block' : 'none';
    confirmBtn.disabled = false;

    // Update button state based on selections
    listEl.querySelectorAll('input[type="checkbox"]').forEach(cb => {
        cb.addEventListener('change', updateImportButtonState);
    });
}

function updateImportButtonState() {
    const checked = document.querySelectorAll('#import-domains-list input[type="checkbox"]:checked');
    document.getElementById('btn-confirm-import').disabled = checked.length === 0;
}

async function confirmImportDomains() {
    const selectedDomains = Array.from(
        document.querySelectorAll('#import-domains-list input[type="checkbox"]:checked')
    ).map(cb => cb.value);

    if (selectedDomains.length === 0) {
        showToast('No domains selected', 'warning');
        return;
    }

    const confirmBtn = document.getElementById('btn-confirm-import');
    confirmBtn.disabled = true;
    confirmBtn.textContent = 'Importing...';

    try {
        const result = await api('/domains/import', {
            method: 'POST',
            body: {
                source_path: importSourcePath,
                domains: selectedDomains
            }
        });

        if (result.success) {
            showToast(`Imported ${result.imported.length} domain(s)`, 'success');
            closeImportDomainsModal();
            await loadDomains(); // Refresh domains list
        } else {
            showToast(result.error || 'Import failed', 'error');
        }
    } catch (err) {
        console.error('Error importing domains:', err);
        showToast('Error: ' + err.message, 'error');
    }

    confirmBtn.disabled = false;
    confirmBtn.textContent = 'Import Selected';
}

// ---- Domain Detail / Rule Editor Functions ----

let currentDetailDomain = null;
let currentDomainData = null;

/**
 * View domain detail - opens rule editor modal
 */
async function viewDomainDetail(name) {
    currentDetailDomain = name;

    const modal = document.getElementById('domain-detail-modal');
    const domainNameEl = document.getElementById('detail-domain-name');
    const rulesListEl = document.getElementById('rules-list');
    const recallInput = document.getElementById('detail-recall');
    const excludeInput = document.getElementById('detail-exclude');
    const configSection = document.querySelector('#domain-detail-modal .detail-section:first-child');
    const rulesSection = document.querySelector('#domain-detail-modal .detail-section:last-child');
    const addRuleBtn = rulesSection?.querySelector('.btn-primary');

    if (!modal) return;

    // Show modal and set loading state
    modal.style.display = 'flex';
    domainNameEl.textContent = name;
    rulesListEl.innerHTML = '<div class="loading">Loading...</div>';
    recallInput.value = '';
    excludeInput.value = '';

    try {
        const result = await api(`/domains/${name}`);

        if (result.error) {
            rulesListEl.innerHTML = `<div class="error">${result.error}</div>`;
            return;
        }

        currentDomainData = result;

        // Hide export button by default (only shown for COMMANDS)
        const sectionHeader = rulesSection.querySelector('.section-header');
        const existingExportBtn = sectionHeader?.querySelector('.btn-export-commands');
        if (existingExportBtn) existingExportBtn.style.display = 'none';

        // Handle special domains differently
        if (name === 'CONTEXT' && result.brackets) {
            configSection.style.display = 'none';
            if (addRuleBtn) addRuleBtn.style.display = 'none';
            rulesSection.querySelector('h4').textContent = 'Context Brackets';
            renderContextBrackets(result.brackets);
        } else if (name === 'COMMANDS' && result.commands) {
            configSection.style.display = 'none';
            if (addRuleBtn) addRuleBtn.textContent = '+ Add Command';
            if (addRuleBtn) addRuleBtn.onclick = () => openAddCommandModal();
            rulesSection.querySelector('h4').textContent = 'Star Commands';

            // Add export button if not already present, or show existing
            let exportBtn = sectionHeader?.querySelector('.btn-export-commands');
            if (!exportBtn && sectionHeader && addRuleBtn) {
                // Create a wrapper to keep both buttons together on the right
                let btnWrapper = sectionHeader.querySelector('.btn-group');
                if (!btnWrapper) {
                    btnWrapper = document.createElement('div');
                    btnWrapper.className = 'btn-group';
                    btnWrapper.style.cssText = 'display: flex; gap: 8px;';
                    addRuleBtn.before(btnWrapper);
                    btnWrapper.appendChild(addRuleBtn);
                }
                exportBtn = document.createElement('button');
                exportBtn.className = 'btn btn-small btn-secondary btn-export-commands';
                exportBtn.textContent = 'Export';
                exportBtn.onclick = () => openExportCommandsModal();
                btnWrapper.insertBefore(exportBtn, addRuleBtn);
            } else if (exportBtn) {
                exportBtn.style.display = 'inline-flex';
            }

            renderCommands(result.commands);
        } else if (name === 'GLOBAL') {
            // GLOBAL domain - show exclude only, no recall (it's always injected)
            configSection.style.display = 'block';
            const recallItem = document.getElementById('config-recall-item');
            const excludeItem = document.getElementById('config-exclude-item');
            if (recallItem) recallItem.style.display = 'none';
            if (excludeItem) excludeItem.style.display = 'block';
            if (addRuleBtn) addRuleBtn.style.display = 'inline-flex';
            if (addRuleBtn) addRuleBtn.textContent = '+ Add Rule';
            if (addRuleBtn) addRuleBtn.onclick = () => addNewRule();
            rulesSection.querySelector('h4').textContent = 'Rules';
            excludeInput.value = result.exclude || '';
            renderRulesList(result.rules || []);
        } else {
            // Standard domain - show both recall and exclude
            configSection.style.display = 'block';
            const recallItem = document.getElementById('config-recall-item');
            const excludeItem = document.getElementById('config-exclude-item');
            if (recallItem) recallItem.style.display = 'block';
            if (excludeItem) excludeItem.style.display = 'block';
            if (addRuleBtn) addRuleBtn.style.display = 'inline-flex';
            if (addRuleBtn) addRuleBtn.textContent = '+ Add Rule';
            if (addRuleBtn) addRuleBtn.onclick = () => addNewRule();
            rulesSection.querySelector('h4').textContent = 'Rules';
            recallInput.value = result.recall || '';
            excludeInput.value = result.exclude || '';
            renderRulesList(result.rules || []);
        }
    } catch (err) {
        console.error('Error loading domain detail:', err);
        rulesListEl.innerHTML = `<div class="error">Error: ${err.message}</div>`;
    }
}

/**
 * Close domain detail modal
 */
function closeDomainDetailModal() {
    const modal = document.getElementById('domain-detail-modal');
    if (modal) {
        modal.style.display = 'none';
    }
    currentDetailDomain = null;
    currentDomainData = null;
}

/**
 * Render CONTEXT brackets
 */
function renderContextBrackets(brackets) {
    const rulesListEl = document.getElementById('rules-list');
    rulesListEl.innerHTML = '';

    const bracketOrder = ['FRESH', 'MODERATE', 'DEPLETED'];
    const descriptions = {
        'FRESH': '60-100% context remaining',
        'MODERATE': '40-60% context remaining',
        'DEPLETED': '25-40% context remaining'
    };

    bracketOrder.forEach(bracket => {
        const data = brackets[bracket] || { enabled: true, rules: [] };
        const div = document.createElement('div');
        div.className = `bracket-section ${data.enabled ? 'enabled' : 'disabled'}`;
        div.dataset.bracket = bracket;

        div.innerHTML = `
            <div class="bracket-header">
                <div class="bracket-info">
                    <span class="bracket-name">${bracket}</span>
                    <span class="bracket-desc">${descriptions[bracket]}</span>
                </div>
                <button class="btn btn-small ${data.enabled ? 'state-active' : 'state-inactive'}"
                        onclick="toggleBracket('${bracket}')">
                    ${data.enabled ? 'Enabled' : 'Disabled'}
                </button>
            </div>
            <div class="bracket-rules">
                ${data.rules.map((rule, i) => {
                    const isFirst = i === 0;
                    const isLast = i === data.rules.length - 1;
                    return `
                    <div class="bracket-rule" data-index="${rule.index}" data-position="${i}">
                        <div class="bracket-rule-reorder">
                            <button class="reorder-btn" onclick="moveBracketRule('${bracket}', ${i}, 'up')" title="Move up" ${isFirst ? 'disabled' : ''}>▲</button>
                            <button class="reorder-btn" onclick="moveBracketRule('${bracket}', ${i}, 'down')" title="Move down" ${isLast ? 'disabled' : ''}>▼</button>
                        </div>
                        <span class="rule-num">${i}</span>
                        <span class="rule-text">${escapeHtml(rule.text)}</span>
                        <div class="bracket-rule-actions">
                            <button class="btn-icon" onclick="editBracketRule('${bracket}', ${rule.index})" title="Edit rule">✎</button>
                            <button class="btn-icon btn-danger" onclick="deleteBracketRule('${bracket}', ${rule.index})" title="Delete rule">✕</button>
                        </div>
                    </div>
                `}).join('') || '<div class="no-rules">No rules defined</div>'}
                <button class="btn btn-small btn-secondary add-bracket-rule-btn"
                        onclick="addBracketRule('${bracket}')">+ Add Rule</button>
            </div>
        `;
        rulesListEl.appendChild(div);
    });
}

/**
 * Toggle a CONTEXT bracket enabled state
 */
async function toggleBracket(bracket) {
    const brackets = currentDomainData?.brackets;
    if (!brackets) return;

    const newEnabled = !brackets[bracket].enabled;

    // Optimistic update
    brackets[bracket].enabled = newEnabled;
    renderContextBrackets(brackets);

    try {
        const result = await api(`/context/brackets/${bracket}`, {
            method: 'PUT',
            body: { enabled: newEnabled }
        });

        if (!result.success) {
            brackets[bracket].enabled = !newEnabled;
            renderContextBrackets(brackets);
            showToast(result.error || 'Failed to update bracket', 'error');
        }
    } catch (err) {
        brackets[bracket].enabled = !newEnabled;
        renderContextBrackets(brackets);
        showToast('Error: ' + err.message, 'error');
    }
}

// Bracket rule modal state
let bracketRuleModalMode = null; // 'add' or 'edit'
let bracketRuleModalBracket = null;
let bracketRuleModalIndex = null;

/**
 * Add a rule to a CONTEXT bracket - opens modal
 */
function addBracketRule(bracket) {
    bracketRuleModalMode = 'add';
    bracketRuleModalBracket = bracket;
    bracketRuleModalIndex = null;

    const modal = document.getElementById('bracket-rule-modal');
    document.getElementById('bracket-rule-modal-title').textContent = `Add Rule to ${bracket}`;
    document.getElementById('bracket-rule-modal-label').textContent = 'Rule Text';
    document.getElementById('bracket-rule-text').value = '';
    document.getElementById('bracket-rule-error').textContent = '';
    document.getElementById('bracket-rule-error').className = 'result-message';
    document.getElementById('btn-confirm-bracket-rule').textContent = 'Add Rule';

    modal.style.display = 'flex';
    document.getElementById('bracket-rule-text').focus();
}

/**
 * Edit a rule in a CONTEXT bracket - opens modal
 */
function editBracketRule(bracket, index) {
    const brackets = currentDomainData?.brackets;
    if (!brackets || !brackets[bracket]) return;

    const rule = brackets[bracket].rules.find(r => r.index === index);
    if (!rule) return;

    bracketRuleModalMode = 'edit';
    bracketRuleModalBracket = bracket;
    bracketRuleModalIndex = index;

    const modal = document.getElementById('bracket-rule-modal');
    document.getElementById('bracket-rule-modal-title').textContent = `Edit Rule in ${bracket}`;
    document.getElementById('bracket-rule-modal-label').textContent = 'Rule Text';
    document.getElementById('bracket-rule-text').value = rule.text;
    document.getElementById('bracket-rule-error').textContent = '';
    document.getElementById('bracket-rule-error').className = 'result-message';
    document.getElementById('btn-confirm-bracket-rule').textContent = 'Save';

    modal.style.display = 'flex';
    document.getElementById('bracket-rule-text').focus();
}

/**
 * Close bracket rule modal
 */
function closeBracketRuleModal() {
    const modal = document.getElementById('bracket-rule-modal');
    if (modal) modal.style.display = 'none';
    bracketRuleModalMode = null;
    bracketRuleModalBracket = null;
    bracketRuleModalIndex = null;
}

/**
 * Confirm bracket rule add/edit
 */
async function confirmBracketRule() {
    const textInput = document.getElementById('bracket-rule-text');
    const errorEl = document.getElementById('bracket-rule-error');
    const confirmBtn = document.getElementById('btn-confirm-bracket-rule');

    const text = textInput.value.trim();
    if (!text) {
        errorEl.textContent = 'Rule text is required';
        errorEl.className = 'result-message error';
        return;
    }

    const brackets = currentDomainData?.brackets;
    if (!brackets || !brackets[bracketRuleModalBracket]) return;

    confirmBtn.disabled = true;
    const originalBtnText = confirmBtn.textContent;
    confirmBtn.textContent = 'Saving...';

    try {
        const rules = brackets[bracketRuleModalBracket].rules || [];

        if (bracketRuleModalMode === 'add') {
            const newIndex = rules.length > 0 ? Math.max(...rules.map(r => r.index)) + 1 : 0;
            rules.push({ index: newIndex, text: text });
        } else if (bracketRuleModalMode === 'edit') {
            const rule = rules.find(r => r.index === bracketRuleModalIndex);
            if (rule) rule.text = text;
        }

        const result = await api(`/context/brackets/${bracketRuleModalBracket}`, {
            method: 'PUT',
            body: { rules: rules }
        });

        if (result.success) {
            const wasAdd = bracketRuleModalMode === 'add';
            brackets[bracketRuleModalBracket].rules = rules;
            renderContextBrackets(brackets);
            closeBracketRuleModal();
            showToast(wasAdd ? 'Rule added' : 'Rule updated', 'success');
        } else {
            errorEl.textContent = result.error || 'Failed to save rule';
            errorEl.className = 'result-message error';
        }
    } catch (err) {
        errorEl.textContent = 'Error: ' + err.message;
        errorEl.className = 'result-message error';
    }

    confirmBtn.disabled = false;
    confirmBtn.textContent = originalBtnText;
}

/**
 * Delete a rule from a CONTEXT bracket (no confirmation dialog)
 */
async function deleteBracketRule(bracket, index) {
    const brackets = currentDomainData?.brackets;
    if (!brackets || !brackets[bracket]) return;

    const rules = brackets[bracket].rules;
    const ruleIndex = rules.findIndex(r => r.index === index);
    if (ruleIndex === -1) return;

    const deletedRule = rules.splice(ruleIndex, 1)[0];

    // Optimistic update
    renderContextBrackets(brackets);

    try {
        const result = await api(`/context/brackets/${bracket}`, {
            method: 'PUT',
            body: { rules: rules }
        });

        if (result.success) {
            showToast('Rule deleted', 'success');
        } else {
            // Rollback
            rules.splice(ruleIndex, 0, deletedRule);
            renderContextBrackets(brackets);
            showToast(result.error || 'Failed to delete rule', 'error');
        }
    } catch (err) {
        // Rollback
        rules.splice(ruleIndex, 0, deletedRule);
        renderContextBrackets(brackets);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Move a bracket rule up or down
 */
async function moveBracketRule(bracket, position, direction) {
    const brackets = currentDomainData?.brackets;
    if (!brackets || !brackets[bracket]) return;

    const rules = brackets[bracket].rules;
    const newPosition = direction === 'up' ? position - 1 : position + 1;

    // Validate bounds
    if (newPosition < 0 || newPosition >= rules.length) return;

    // Swap rules
    [rules[position], rules[newPosition]] = [rules[newPosition], rules[position]];

    // Update indices to match new positions
    rules.forEach((rule, i) => { rule.index = i; });

    // Optimistic update
    renderContextBrackets(brackets);

    try {
        const result = await api(`/context/brackets/${bracket}`, {
            method: 'PUT',
            body: { rules: rules }
        });

        if (!result.success) {
            // Revert
            [rules[position], rules[newPosition]] = [rules[newPosition], rules[position]];
            rules.forEach((rule, i) => { rule.index = i; });
            renderContextBrackets(brackets);
            showToast(result.error || 'Failed to reorder rules', 'error');
        }
    } catch (err) {
        // Revert
        [rules[position], rules[newPosition]] = [rules[newPosition], rules[position]];
        rules.forEach((rule, i) => { rule.index = i; });
        renderContextBrackets(brackets);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Render COMMANDS list
 */
function renderCommands(commands) {
    const rulesListEl = document.getElementById('rules-list');

    // Get command order (excluding _order key)
    const commandOrder = commands._order || Object.keys(commands).filter(k => k !== '_order').sort();
    const actualCommands = commandOrder.filter(cmd => commands[cmd]);

    if (actualCommands.length === 0) {
        rulesListEl.innerHTML = '<div class="no-rules">No commands defined</div>';
        return;
    }

    rulesListEl.innerHTML = '';

    actualCommands.forEach((cmd, idx) => {
        const data = commands[cmd];
        const div = document.createElement('div');
        div.className = 'command-section';
        div.dataset.command = cmd;

        const isFirst = idx === 0;
        const isLast = idx === actualCommands.length - 1;

        div.innerHTML = `
            <div class="command-header">
                <div class="command-reorder">
                    <button class="reorder-btn" onclick="event.stopPropagation(); moveCommand('${cmd}', 'up')" title="Move up" ${isFirst ? 'disabled' : ''}>▲</button>
                    <button class="reorder-btn" onclick="event.stopPropagation(); moveCommand('${cmd}', 'down')" title="Move down" ${isLast ? 'disabled' : ''}>▼</button>
                </div>
                <div class="command-info" onclick="toggleCommandExpand('${cmd}')">
                    <span class="command-name">*${cmd.toLowerCase()}</span>
                    <span class="command-count">${data.rules.length} rule${data.rules.length !== 1 ? 's' : ''}</span>
                </div>
                <span class="expand-icon" onclick="toggleCommandExpand('${cmd}')">▼</span>
            </div>
            <div class="command-rules" style="display: none;">
                ${data.rules.map((rule, i) => `
                    <div class="command-rule" data-index="${rule.index}">
                        <span class="rule-num">${rule.index}</span>
                        <span class="rule-text">${rule.text}</span>
                    </div>
                `).join('')}
                <div class="command-actions">
                    <button class="btn btn-small btn-secondary" onclick="openEditCommandModal('${cmd}')">Edit</button>
                    <button class="btn btn-small btn-danger" onclick="deleteCommand('${cmd}')">Delete</button>
                </div>
            </div>
        `;
        rulesListEl.appendChild(div);
    });
}

/**
 * Toggle command expansion
 */
function toggleCommandExpand(cmd) {
    const section = document.querySelector(`.command-section[data-command="${cmd}"]`);
    if (!section) return;

    const rulesDiv = section.querySelector('.command-rules');
    const icon = section.querySelector('.expand-icon');

    if (rulesDiv.style.display === 'none') {
        rulesDiv.style.display = 'block';
        icon.textContent = '▲';
    } else {
        rulesDiv.style.display = 'none';
        icon.textContent = '▼';
    }
}

/**
 * Delete a star command
 */
let pendingDeleteCommand = null;

function deleteCommand(cmd) {
    pendingDeleteCommand = cmd;
    document.getElementById('delete-command-name').textContent = `*${cmd.toLowerCase()}`;
    document.getElementById('delete-command-modal').style.display = 'flex';
}

function closeDeleteCommandModal() {
    document.getElementById('delete-command-modal').style.display = 'none';
    pendingDeleteCommand = null;
}

async function confirmDeleteCommand() {
    if (!pendingDeleteCommand) return;

    const cmd = pendingDeleteCommand;
    closeDeleteCommandModal();

    try {
        const result = await api(`/commands/${cmd}`, { method: 'DELETE' });

        if (result.success) {
            delete currentDomainData.commands[cmd];
            // Also remove from order
            if (currentDomainData.commands._order) {
                currentDomainData.commands._order = currentDomainData.commands._order.filter(c => c !== cmd);
            }
            renderCommands(currentDomainData.commands);
            showToast('Command deleted', 'success');
        } else {
            showToast(result.error || 'Failed to delete command', 'error');
        }
    } catch (err) {
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Move a command up or down (optimistic update)
 */
async function moveCommand(cmd, direction) {
    const commands = currentDomainData.commands;
    if (!commands) return;

    // Get current order
    const order = commands._order || Object.keys(commands).filter(k => k !== '_order').sort();
    const currentIndex = order.indexOf(cmd);

    if (currentIndex === -1) return;
    if (direction === 'up' && currentIndex === 0) return;
    if (direction === 'down' && currentIndex === order.length - 1) return;

    // Calculate new index
    const newIndex = direction === 'up' ? currentIndex - 1 : currentIndex + 1;

    // Save original order for rollback
    const originalOrder = [...order];

    // Optimistic update: swap positions
    const newOrder = [...order];
    [newOrder[currentIndex], newOrder[newIndex]] = [newOrder[newIndex], newOrder[currentIndex]];

    // Update local data and re-render immediately
    commands._order = newOrder;
    renderCommands(commands);

    // Make API call in background
    try {
        const result = await api('/commands/reorder', {
            method: 'POST',
            body: { order: newOrder }
        });

        if (!result.success) {
            // Rollback on failure
            commands._order = originalOrder;
            renderCommands(commands);
            showToast(result.error || 'Failed to reorder commands', 'error');
        }
    } catch (err) {
        // Rollback on error
        commands._order = originalOrder;
        renderCommands(commands);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Open add command modal
 */
function openAddCommandModal() {
    const modal = document.getElementById('add-command-modal');
    if (modal) {
        modal.style.display = 'flex';
        document.getElementById('new-command-name').value = '';
        document.getElementById('new-command-rule').value = '';
        document.getElementById('add-command-error').textContent = '';
        document.getElementById('new-command-name').focus();
    }
}

/**
 * Close add command modal
 */
function closeAddCommandModal() {
    const modal = document.getElementById('add-command-modal');
    if (modal) modal.style.display = 'none';
}

/**
 * Confirm and create new command
 */
async function confirmAddCommand() {
    const nameInput = document.getElementById('new-command-name');
    const ruleInput = document.getElementById('new-command-rule');
    const errorEl = document.getElementById('add-command-error');

    const name = nameInput.value.trim().toUpperCase().replace(/^\*/, '');
    const rule = ruleInput.value.trim();

    // Validation
    if (!name) {
        errorEl.textContent = 'Please enter a command name';
        errorEl.className = 'result-message error';
        nameInput.focus();
        return;
    }

    if (!/^[A-Z][A-Z0-9_]*$/.test(name)) {
        errorEl.textContent = 'Command name must start with a letter and contain only letters, numbers, underscores';
        errorEl.className = 'result-message error';
        nameInput.focus();
        return;
    }

    if (!rule) {
        errorEl.textContent = 'Please enter at least one rule';
        errorEl.className = 'result-message error';
        ruleInput.focus();
        return;
    }

    // Check for duplicate
    if (currentDomainData.commands && currentDomainData.commands[name]) {
        errorEl.textContent = `Command *${name.toLowerCase()} already exists`;
        errorEl.className = 'result-message error';
        return;
    }

    try {
        const result = await api(`/commands/${name}`, {
            method: 'PUT',
            body: { rules: [{ index: 0, text: rule }] }
        });

        if (result.success) {
            // Add to local data and re-render
            if (!currentDomainData.commands) currentDomainData.commands = {};
            currentDomainData.commands[name] = { rules: [{ index: 0, text: rule }] };
            // Add to order (at end)
            if (!currentDomainData.commands._order) {
                currentDomainData.commands._order = [];
            }
            currentDomainData.commands._order.push(name);
            renderCommands(currentDomainData.commands);
            closeAddCommandModal();
        } else {
            errorEl.textContent = 'Error: ' + (result.error || 'Failed to create command');
            errorEl.className = 'result-message error';
        }
    } catch (err) {
        errorEl.textContent = 'Error: ' + err.message;
        errorEl.className = 'result-message error';
    }
}

// ---- Edit Command Functions ----

let editingCommandName = null;

/**
 * Open edit command modal
 */
function openEditCommandModal(cmd) {
    const modal = document.getElementById('edit-command-modal');
    if (!modal) return;

    editingCommandName = cmd;
    const commandData = currentDomainData.commands?.[cmd];
    if (!commandData) {
        showToast('Command not found', 'error');
        return;
    }

    // Set title and name input
    document.getElementById('edit-command-title').textContent = `*${cmd.toLowerCase()}`;
    document.getElementById('edit-command-name').value = cmd.toLowerCase();

    // Render rules
    const rulesList = document.getElementById('edit-command-rules');
    rulesList.innerHTML = '';

    commandData.rules.forEach((rule, i) => {
        rulesList.appendChild(createEditRuleRow(i, rule.text));
    });

    modal.style.display = 'flex';
}

/**
 * Close edit command modal
 */
function closeEditCommandModal() {
    const modal = document.getElementById('edit-command-modal');
    if (modal) modal.style.display = 'none';
    editingCommandName = null;
}

/**
 * Create an editable rule row
 */
function createEditRuleRow(index, text = '') {
    const div = document.createElement('div');
    div.className = 'edit-rule-row';
    div.dataset.index = index;
    div.innerHTML = `
        <span class="rule-num">${index}</span>
        <textarea class="edit-rule-text" rows="2" placeholder="Rule instruction...">${escapeHtml(text)}</textarea>
        <button type="button" class="btn-icon btn-remove-rule" onclick="removeEditRule(this)" title="Remove rule">&times;</button>
    `;
    return div;
}

/**
 * Add a new rule row in edit modal
 */
function addEditRule() {
    const rulesList = document.getElementById('edit-command-rules');
    const rows = rulesList.querySelectorAll('.edit-rule-row');
    const nextIndex = rows.length;
    rulesList.appendChild(createEditRuleRow(nextIndex, ''));

    // Focus the new textarea
    const newRow = rulesList.lastElementChild;
    newRow.querySelector('textarea').focus();
}

/**
 * Remove a rule row in edit modal
 */
function removeEditRule(btn) {
    const row = btn.closest('.edit-rule-row');
    row.remove();

    // Renumber remaining rows
    const rulesList = document.getElementById('edit-command-rules');
    rulesList.querySelectorAll('.edit-rule-row').forEach((r, i) => {
        r.dataset.index = i;
        r.querySelector('.rule-num').textContent = i;
    });
}

/**
 * Save edited command
 */
async function saveEditCommand() {
    const newName = document.getElementById('edit-command-name').value.trim().toUpperCase();
    const rulesList = document.getElementById('edit-command-rules');

    if (!newName) {
        showToast('Command name is required', 'warning');
        return;
    }

    // Check for name conflict if renamed
    if (newName !== editingCommandName && currentDomainData.commands?.[newName]) {
        showToast(`Command *${newName.toLowerCase()} already exists`, 'error');
        return;
    }

    // Collect rules
    const rules = [];
    rulesList.querySelectorAll('.edit-rule-row').forEach((row, i) => {
        const text = row.querySelector('textarea').value.trim();
        if (text) {
            rules.push({ index: i, text: text });
        }
    });

    if (rules.length === 0) {
        showToast('At least one rule is required', 'warning');
        return;
    }

    try {
        // If renamed, delete old and create new
        if (newName !== editingCommandName) {
            // Delete old command
            await api(`/commands/${editingCommandName}`, { method: 'DELETE' });

            // Create with new name
            const result = await api(`/commands/${newName}`, {
                method: 'PUT',
                body: { rules }
            });

            if (result.success) {
                // Update local data
                delete currentDomainData.commands[editingCommandName];
                currentDomainData.commands[newName] = { rules };

                // Update order
                if (currentDomainData.commands._order) {
                    const idx = currentDomainData.commands._order.indexOf(editingCommandName);
                    if (idx >= 0) {
                        currentDomainData.commands._order[idx] = newName;
                    }
                }

                renderCommands(currentDomainData.commands);
                closeEditCommandModal();
                showToast(`Renamed to *${newName.toLowerCase()} and saved`, 'success');
            } else {
                showToast(result.error || 'Failed to save command', 'error');
            }
        } else {
            // Just update rules
            const result = await api(`/commands/${newName}`, {
                method: 'PUT',
                body: { rules }
            });

            if (result.success) {
                currentDomainData.commands[newName] = { rules };
                renderCommands(currentDomainData.commands);
                closeEditCommandModal();
                showToast('Command saved', 'success');
            } else {
                showToast(result.error || 'Failed to save command', 'error');
            }
        }
    } catch (err) {
        showToast('Error: ' + err.message, 'error');
    }
}

// ---- Export Commands Functions ----

/**
 * Open export commands modal
 */
function openExportCommandsModal() {
    const modal = document.getElementById('export-commands-modal');
    if (!modal) return;

    // Clear inputs
    document.getElementById('export-commands-name').value = '';
    document.getElementById('export-commands-description').value = '';

    // Populate command list
    const listEl = document.getElementById('export-commands-list');
    listEl.innerHTML = '';

    const commands = currentDomainData.commands;
    if (!commands) {
        listEl.innerHTML = '<div class="no-rules">No commands to export</div>';
        modal.style.display = 'flex';
        return;
    }

    const commandOrder = commands._order || Object.keys(commands).filter(k => k !== '_order').sort();
    const actualCommands = commandOrder.filter(cmd => commands[cmd]);

    actualCommands.forEach(cmd => {
        const data = commands[cmd];
        const rules = data.rules || [];
        const ruleTexts = rules.slice(0, 7).map((r, i) => {
            const text = typeof r === 'string' ? r : r.text || '';
            const truncated = text.length > 140 ? text.substring(0, 140) + '...' : text;
            return `<div class="tooltip-rule"><span class="tooltip-rule-num">${i}</span>${escapeHtml(truncated)}</div>`;
        }).join('');
        const moreText = rules.length > 7 ? `<div class="tooltip-more">+${rules.length - 7} more...</div>` : '';

        const label = document.createElement('label');
        label.className = 'checkbox-item';
        label.innerHTML = `
            <input type="checkbox" name="export-command" value="${cmd}" checked>
            <span class="checkbox-label">
                <span class="command-name">*${cmd.toLowerCase()}</span>
                <span class="checkbox-meta">${rules.length} rule${rules.length !== 1 ? 's' : ''}</span>
                <span class="rules-tooltip-trigger" onmouseenter="positionTooltip(event)" onclick="event.preventDefault()">
                    <span class="info-icon">ⓘ</span>
                    <div class="rules-tooltip">${ruleTexts}${moreText}</div>
                </span>
            </span>
        `;
        listEl.appendChild(label);
    });

    modal.style.display = 'flex';
}

/**
 * Close export commands modal
 */
function closeExportCommandsModal() {
    const modal = document.getElementById('export-commands-modal');
    if (modal) modal.style.display = 'none';
}

/**
 * Select all or none export commands
 */
function selectAllExportCommands(selectAll) {
    document.querySelectorAll('input[name="export-command"]').forEach(cb => {
        cb.checked = selectAll;
    });
}

/**
 * Export selected commands as addon and trigger download
 */
async function exportCommands() {
    const name = document.getElementById('export-commands-name').value.trim();
    const description = document.getElementById('export-commands-description').value.trim();

    if (!name) {
        showToast('Please enter an addon name', 'warning');
        return;
    }

    // Collect selected commands
    const selectedCommands = [];
    document.querySelectorAll('input[name="export-command"]:checked').forEach(cb => {
        selectedCommands.push(cb.value);
    });

    if (selectedCommands.length === 0) {
        showToast('Please select at least one command to export', 'warning');
        return;
    }

    // Build addon JSON
    const commands = currentDomainData.commands;
    const commandsData = {};
    selectedCommands.forEach(cmd => {
        if (commands[cmd]) {
            commandsData[cmd] = { rules: commands[cmd].rules };
        }
    });

    const addon = {
        version: "1.0",
        type: "carl-addon",
        addon_subtype: "commands",
        metadata: {
            name: name,
            description: description,
            author: "",
            created: new Date().toISOString(),
            tags: ["commands"]
        },
        domains: [],
        special_domains: {
            COMMANDS: {
                commands: commandsData
            }
        },
        manifest_settings: {},
        optional_hooks: []
    };

    const jsonContent = JSON.stringify(addon, null, 2);
    const filename = name.toLowerCase().replace(/[^a-z0-9]+/g, '-') + '.json';

    try {
        // Save to addons directory
        const result = await api('/addons/save', {
            method: 'POST',
            body: { content: jsonContent, filename: filename }
        });

        if (result.success) {
            closeExportCommandsModal();
            showToast(`Exported "${name}" to addons library`, 'success');

            // Also offer download
            const blob = new Blob([jsonContent], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            a.click();
            URL.revokeObjectURL(url);
        } else {
            showToast('Error saving addon: ' + (result.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        showToast('Error exporting: ' + err.message, 'error');
    }
}

/**
 * Render the rules list
 */
function renderRulesList(rules) {
    const rulesListEl = document.getElementById('rules-list');

    if (!rules || rules.length === 0) {
        rulesListEl.innerHTML = '<div class="no-rules">No rules defined. Click "+ Add Rule" to create one.</div>';
        return;
    }

    rulesListEl.innerHTML = '';
    rules.forEach((rule, index) => {
        rulesListEl.appendChild(renderRuleItem(rule, index));
    });
}

/**
 * Render a single rule item
 */
function renderRuleItem(rule, index) {
    const div = document.createElement('div');
    div.className = 'rule-item';
    div.dataset.index = index;

    const ruleText = rule.text || '';
    const isFirst = index === 0;
    const totalRules = currentDomainData?.rules?.length || 0;
    const isLast = index === totalRules - 1;

    div.innerHTML = `
        <div class="rule-reorder">
            <button class="reorder-btn" onclick="moveRule(${index}, 'up')" title="Move up" ${isFirst ? 'disabled' : ''}>▲</button>
            <button class="reorder-btn" onclick="moveRule(${index}, 'down')" title="Move down" ${isLast ? 'disabled' : ''}>▼</button>
        </div>
        <div class="rule-index">${index}</div>
        <div class="rule-content">
            <div class="rule-text ${!ruleText ? 'placeholder' : ''}">${ruleText || '(empty rule)'}</div>
        </div>
        <div class="rule-actions">
            <button class="rule-action-btn" onclick="editRule(${index})" title="Edit">Edit</button>
            <button class="rule-action-btn delete" onclick="deleteRule(${index})" title="Delete"
                    ${isFirst ? 'disabled title="Cannot delete Rule 0 (description)"' : ''}>Del</button>
        </div>
    `;

    return div;
}

/**
 * Edit a rule inline
 */
function editRule(index) {
    const ruleItem = document.querySelector(`.rule-item[data-index="${index}"]`);
    if (!ruleItem || ruleItem.classList.contains('editing')) return;

    const rule = currentDomainData?.rules?.[index];
    const currentText = rule?.text || '';

    ruleItem.classList.add('editing');

    const contentEl = ruleItem.querySelector('.rule-content');
    contentEl.innerHTML = `
        <textarea class="rule-edit-input" id="rule-edit-${index}">${currentText}</textarea>
        <div class="rule-edit-actions">
            <button class="rule-action-btn save" onclick="saveRuleEdit(${index})">Save</button>
            <button class="rule-action-btn cancel" onclick="cancelRuleEdit(${index})">Cancel</button>
        </div>
    `;

    // Focus and select the textarea
    const textarea = document.getElementById(`rule-edit-${index}`);
    if (textarea) {
        textarea.focus();
        textarea.select();
    }

    // Hide the action buttons while editing
    const actionsEl = ruleItem.querySelector('.rule-actions');
    if (actionsEl) actionsEl.style.display = 'none';
}

/**
 * Cancel rule edit
 */
function cancelRuleEdit(index) {
    const ruleItem = document.querySelector(`.rule-item[data-index="${index}"]`);
    if (!ruleItem) return;

    // Re-render the rule item
    const rule = currentDomainData?.rules?.[index];
    const newItem = renderRuleItem(rule, index);
    ruleItem.replaceWith(newItem);
}

/**
 * Save rule edit
 */
async function saveRuleEdit(index) {
    const textarea = document.getElementById(`rule-edit-${index}`);
    if (!textarea) return;

    const newText = textarea.value.trim();
    const saveBtn = document.querySelector(`.rule-item[data-index="${index}"] .rule-action-btn.save`);

    if (saveBtn) {
        saveBtn.disabled = true;
        saveBtn.textContent = 'Saving...';
    }

    try {
        const result = await api(`/domains/${currentDetailDomain}/rules/${index}`, {
            method: 'PUT',
            body: { text: newText }
        });

        if (result.success) {
            // Update local data
            if (currentDomainData?.rules?.[index]) {
                currentDomainData.rules[index].text = newText;
            }
            // Re-render the rule item
            cancelRuleEdit(index);
        } else {
            showToast(result.error || 'Failed to save rule', 'error');
            if (saveBtn) {
                saveBtn.disabled = false;
                saveBtn.textContent = 'Save';
            }
        }
    } catch (err) {
        console.error('Error saving rule:', err);
        showToast('Error: ' + err.message, 'error');
        if (saveBtn) {
            saveBtn.disabled = false;
            saveBtn.textContent = 'Save';
        }
    }
}

/**
 * Delete a rule - show confirmation modal
 */
let pendingDeleteRuleIndex = null;

function deleteRule(index) {
    if (index === 0) {
        showToast('Cannot delete Rule 0 (domain description)', 'warning');
        return;
    }

    pendingDeleteRuleIndex = index;
    document.getElementById('delete-rule-index').textContent = index;
    document.getElementById('delete-rule-modal').style.display = 'flex';
}

function closeDeleteRuleModal() {
    pendingDeleteRuleIndex = null;
    document.getElementById('delete-rule-modal').style.display = 'none';
}

async function confirmDeleteRule() {
    if (pendingDeleteRuleIndex === null) return;

    const confirmBtn = document.getElementById('btn-confirm-delete-rule');
    confirmBtn.disabled = true;
    confirmBtn.textContent = 'Deleting...';

    try {
        const result = await api(`/domains/${currentDetailDomain}/rules/${pendingDeleteRuleIndex}`, {
            method: 'DELETE'
        });

        if (result.success) {
            closeDeleteRuleModal();
            // Reload domain detail to refresh rules
            await viewDomainDetail(currentDetailDomain);
        } else {
            showToast(result.error || 'Failed to delete rule', 'error');
        }
    } catch (err) {
        console.error('Error deleting rule:', err);
        showToast('Error: ' + err.message, 'error');
    }

    confirmBtn.disabled = false;
    confirmBtn.textContent = 'Delete';
}

/**
 * Move a rule up or down
 */
async function moveRule(index, direction) {
    const rules = currentDomainData?.rules || [];
    const newIndex = direction === 'up' ? index - 1 : index + 1;

    // Validate bounds
    if (newIndex < 0 || newIndex >= rules.length) return;

    // Swap in local array first (optimistic update)
    [rules[index], rules[newIndex]] = [rules[newIndex], rules[index]];

    // Re-render immediately without refresh
    renderRulesList(rules);

    // Build order for API (original indices before swap)
    const order = rules.map((_, i) => i);
    // The API expects the new positions, so we need to swap back conceptually
    // Actually, we already swapped the array, so we send the current indices
    // But the API expects: order[newPosition] = originalIndex
    // Since we swapped locally, we need to tell API the mapping
    // Simpler: just send indices in new order
    const apiOrder = [];
    for (let i = 0; i < rules.length; i++) {
        if (i === index) apiOrder.push(newIndex);
        else if (i === newIndex) apiOrder.push(index);
        else apiOrder.push(i);
    }

    try {
        const result = await api(`/domains/${currentDetailDomain}/rules/reorder`, {
            method: 'POST',
            body: { order: apiOrder }
        });

        if (!result.success) {
            // Revert on failure
            [rules[index], rules[newIndex]] = [rules[newIndex], rules[index]];
            renderRulesList(rules);
            showToast(result.error || 'Failed to reorder rules', 'error');
        }
    } catch (err) {
        // Revert on error
        [rules[index], rules[newIndex]] = [rules[newIndex], rules[index]];
        renderRulesList(rules);
        console.error('Error reordering rules:', err);
        showToast('Error: ' + err.message, 'error');
    }
}

/**
 * Open add rule modal
 */
function addNewRule() {
    const modal = document.getElementById('add-rule-modal');
    if (modal) {
        modal.style.display = 'flex';
        document.getElementById('new-rule-text').value = '';
        document.getElementById('add-rule-error').textContent = '';
        document.getElementById('add-rule-error').className = 'result-message';
        document.getElementById('new-rule-text').focus();
    }
}

/**
 * Close add rule modal
 */
function closeAddRuleModal() {
    const modal = document.getElementById('add-rule-modal');
    if (modal) {
        modal.style.display = 'none';
    }
}

/**
 * Confirm and add new rule
 */
async function confirmAddRule() {
    const textInput = document.getElementById('new-rule-text');
    const errorEl = document.getElementById('add-rule-error');
    const confirmBtn = document.getElementById('btn-confirm-add-rule');

    const text = textInput.value.trim();

    if (!text) {
        errorEl.textContent = 'Rule text is required';
        errorEl.className = 'result-message error';
        return;
    }

    confirmBtn.disabled = true;
    confirmBtn.textContent = 'Adding...';

    try {
        const result = await api(`/domains/${currentDetailDomain}/rules`, {
            method: 'POST',
            body: { text: text }
        });

        if (result.success) {
            closeAddRuleModal();
            // Reload domain detail to refresh rules
            await viewDomainDetail(currentDetailDomain);
        } else {
            errorEl.textContent = result.error || 'Failed to add rule';
            errorEl.className = 'result-message error';
        }
    } catch (err) {
        console.error('Error adding rule:', err);
        errorEl.textContent = 'Error: ' + err.message;
        errorEl.className = 'result-message error';
    }

    confirmBtn.disabled = false;
    confirmBtn.textContent = 'Add Rule';
}

/**
 * Save domain configuration (recall, exclude keywords)
 */
async function saveDomainConfig() {
    const recallInput = document.getElementById('detail-recall');
    const excludeInput = document.getElementById('detail-exclude');
    const saveBtn = document.getElementById('btn-save-config');
    const statusEl = document.getElementById('config-save-status');

    const recall = recallInput.value.trim();
    const exclude = excludeInput.value.trim();

    if (!recall) {
        statusEl.textContent = 'Recall keywords required';
        statusEl.className = 'save-status-inline error';
        return;
    }

    saveBtn.disabled = true;
    saveBtn.textContent = 'Saving...';
    statusEl.textContent = '';

    try {
        const result = await api(`/domains/${currentDetailDomain}`, {
            method: 'PUT',
            body: { recall: recall, exclude: exclude || null }
        });

        if (result.success) {
            statusEl.textContent = 'Saved!';
            statusEl.className = 'save-status-inline success';
            // Update local data
            if (currentDomainData) {
                currentDomainData.recall = recall;
                currentDomainData.exclude = exclude;
            }
            // Refresh the domains list in the background
            loadDomains();
        } else {
            statusEl.textContent = result.error || 'Save failed';
            statusEl.className = 'save-status-inline error';
        }
    } catch (err) {
        console.error('Error saving config:', err);
        statusEl.textContent = 'Error: ' + err.message;
        statusEl.className = 'save-status-inline error';
    }

    saveBtn.disabled = false;
    saveBtn.textContent = 'Save Config';

    // Clear status after 3 seconds
    setTimeout(() => {
        statusEl.textContent = '';
        statusEl.className = 'save-status-inline';
    }, 3000);
}

/**
 * Open create domain modal
 */
function openCreateDomainModal() {
    const modal = document.getElementById('create-domain-modal');
    if (modal) {
        modal.style.display = 'flex';
        // Clear form
        document.getElementById('domain-name').value = '';
        document.getElementById('domain-recall').value = '';
        document.getElementById('domain-rules').value = '';
        document.getElementById('create-domain-error').textContent = '';
        document.getElementById('create-domain-error').className = 'result-message';
        // Focus name input
        document.getElementById('domain-name').focus();
    }
}

/**
 * Close create domain modal
 */
function closeCreateDomainModal() {
    const modal = document.getElementById('create-domain-modal');
    if (modal) {
        modal.style.display = 'none';
    }
}

/**
 * Confirm and create domain
 */
async function confirmCreateDomain() {
    const nameInput = document.getElementById('domain-name');
    const recallInput = document.getElementById('domain-recall');
    const rulesInput = document.getElementById('domain-rules');
    const errorEl = document.getElementById('create-domain-error');
    const confirmBtn = document.getElementById('btn-confirm-create');

    const name = nameInput.value.trim();
    const recall = recallInput.value.trim();
    const rulesText = rulesInput.value.trim();

    // Validate
    if (!name) {
        errorEl.textContent = 'Domain name is required';
        errorEl.className = 'result-message error';
        return;
    }

    if (!recall) {
        errorEl.textContent = 'At least one recall keyword is required';
        errorEl.className = 'result-message error';
        return;
    }

    // Parse rules (one per line)
    const rules = rulesText ? rulesText.split('\n').filter(r => r.trim()) : [];

    confirmBtn.disabled = true;
    confirmBtn.textContent = 'Creating...';

    try {
        const result = await api('/domains', {
            method: 'POST',
            body: {
                name: name,
                recall: recall,
                rules: rules,
                state: true
            }
        });

        if (result.success) {
            closeCreateDomainModal();
            await loadDomains();
        } else {
            errorEl.textContent = result.error || 'Failed to create domain';
            errorEl.className = 'result-message error';
        }
    } catch (err) {
        console.error('Error creating domain:', err);
        errorEl.textContent = 'Error: ' + err.message;
        errorEl.className = 'result-message error';
    }

    confirmBtn.disabled = false;
    confirmBtn.textContent = 'Create Domain';
}

/**
 * Open delete confirmation modal
 */
function deleteDomain(name) {
    pendingDeleteDomain = name;
    const modal = document.getElementById('delete-domain-modal');
    const nameEl = document.getElementById('delete-domain-name');
    if (modal && nameEl) {
        nameEl.textContent = name;
        modal.style.display = 'flex';
    }
}

/**
 * Close delete confirmation modal
 */
function closeDeleteDomainModal() {
    pendingDeleteDomain = null;
    const modal = document.getElementById('delete-domain-modal');
    if (modal) {
        modal.style.display = 'none';
    }
}

/**
 * Confirm and delete domain
 */
async function confirmDeleteDomain() {
    if (!pendingDeleteDomain) return;

    const confirmBtn = document.getElementById('btn-confirm-delete');
    confirmBtn.disabled = true;
    confirmBtn.textContent = 'Deleting...';

    try {
        const result = await api(`/domains/${pendingDeleteDomain}`, {
            method: 'DELETE'
        });

        if (result.success) {
            closeDeleteDomainModal();
            await loadDomains();
        } else {
            showToast(result.error || 'Failed to delete domain', 'error');
        }
    } catch (err) {
        console.error('Error deleting domain:', err);
        showToast('Error: ' + err.message, 'error');
    }

    confirmBtn.disabled = false;
    confirmBtn.textContent = 'Delete';
}

// ---- Addons Functions ----

// Addons state
let currentPreviewPath = null;
let currentPreviewData = null;
let exportedAddonContent = null;
let exportedAddonFilename = null;

/**
 * Load available and installed addons
 */
async function loadAddons() {
    if (!isConnected) return;

    const installedList = document.getElementById('installed-addons-list');
    const availableList = document.getElementById('available-addons-list');
    const noInstalled = document.getElementById('no-installed-addons');
    const noAvailable = document.getElementById('no-available-addons');
    const installedPacksCard = document.getElementById('installed-packs-card');

    if (installedList) installedList.innerHTML = '<div class="loading">Loading installed addons...</div>';
    if (availableList) availableList.innerHTML = '<div class="loading">Loading available addons...</div>';
    if (noInstalled) noInstalled.style.display = 'none';
    if (noAvailable) noAvailable.style.display = 'none';

    try {
        const result = await api('/addons');

        if (!result.success) {
            if (installedList) installedList.innerHTML = `<div class="error">${result.error}</div>`;
            if (availableList) availableList.innerHTML = '';
            return;
        }

        const installed = result.installed || [];
        const available = result.available || [];

        // Render installed addons - hide entire section if none installed
        if (installed.length === 0) {
            if (installedPacksCard) installedPacksCard.style.display = 'none';
            if (installedList) installedList.innerHTML = '';
            if (noInstalled) noInstalled.style.display = 'none';
        } else {
            if (installedPacksCard) installedPacksCard.style.display = '';
            if (installedList) {
                installedList.innerHTML = '';
                installed.forEach(addon => {
                    installedList.appendChild(renderInstalledAddon(addon));
                });
            }
        }

        // Render available addons (filter out already installed)
        const notInstalled = available.filter(a => !a.installed);
        if (notInstalled.length === 0) {
            if (availableList) availableList.innerHTML = '';
            if (noAvailable) noAvailable.style.display = 'block';
        } else {
            if (availableList) {
                availableList.innerHTML = '';
                notInstalled.forEach(addon => {
                    availableList.appendChild(renderAvailableAddon(addon));
                });
            }
        }
    } catch (err) {
        console.error('Error loading addons:', err);
        if (installedList) installedList.innerHTML = '<div class="error">Error loading addons</div>';
    }
}

/**
 * Render an installed addon card
 */
function renderInstalledAddon(addon) {
    const div = document.createElement('div');
    div.className = 'addon-card installed';
    div.dataset.name = addon.name;

    // Check if this is a COMMANDS addon (has commands_owned)
    const isCommandsAddon = addon.type === 'commands' || addon.commands_owned;
    const commandCount = addon.commands_owned ? Object.keys(addon.commands_owned).length : 0;

    // Build metrics - show domains and/or commands
    const metrics = [];
    if (addon.domains && addon.domains.length > 0) {
        metrics.push(`${addon.domains.length} domain${addon.domains.length !== 1 ? 's' : ''}`);
    }
    if (isCommandsAddon && commandCount > 0) {
        metrics.push(`${commandCount} command${commandCount !== 1 ? 's' : ''} active`);
    } else if (addon.commands_added && addon.commands_added.length > 0) {
        // Legacy format support
        metrics.push(`${addon.commands_added.length} command${addon.commands_added.length !== 1 ? 's' : ''}`);
    }
    const metricsText = metrics.length > 0 ? metrics.join(', ') : 'installed';

    // Install/update date
    const dateField = addon.updated_at || addon.installed_at;
    const dateLabel = addon.updated_at ? 'Updated' : 'Installed';
    const dateText = dateField ? new Date(dateField).toLocaleDateString() : '';

    // Escape source file path for onclick
    const sourcePath = addon.source_file ? addon.source_file.replace(/\\/g, '\\\\').replace(/'/g, "\\'") : '';

    // Button text based on addon type
    const buttonText = isCommandsAddon ? 'Edit Settings' : 'View / Add More';

    div.innerHTML = `
        <div class="addon-info">
            <span class="addon-name">${addon.name}</span>
            ${isCommandsAddon ? '<span class="addon-type-badge">commands</span>' : ''}
            <span class="addon-meta">${metricsText}</span>
            ${dateText ? `<span class="addon-date">${dateLabel}: ${dateText}</span>` : ''}
        </div>
        <div class="addon-actions">
            ${sourcePath ? `<button class="btn btn-small btn-secondary" onclick="previewAddon('${sourcePath}')">${buttonText}</button>` : ''}
            <button class="btn btn-small btn-danger" onclick="uninstallAddon('${addon.name.replace(/'/g, "\\'")}')">Uninstall</button>
        </div>
    `;

    return div;
}

/**
 * Render an available addon card
 */
function renderAvailableAddon(addon) {
    const div = document.createElement('div');
    div.className = 'addon-card';
    div.dataset.path = addon.path;

    const tags = addon.tags && addon.tags.length > 0
        ? `<div class="addon-tags">${addon.tags.map(t => `<span class="tag">${t}</span>`).join('')}</div>`
        : '';

    div.innerHTML = `
        <div class="addon-info">
            <span class="addon-name">${addon.name}</span>
            <span class="addon-description">${addon.description || ''}</span>
            <span class="addon-meta">${addon.domain_count} domain${addon.domain_count !== 1 ? 's' : ''} ${addon.source === 'bundled' ? '(bundled)' : ''}</span>
            ${tags}
        </div>
        <div class="addon-actions">
            <button class="btn btn-small btn-secondary" onclick="previewAddon('${addon.path.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}')">Preview</button>
            <button class="btn btn-small btn-primary" onclick="quickInstallAddon('${addon.path.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}')">Install</button>
        </div>
    `;

    return div;
}

/**
 * Preview an addon before installation
 */
async function previewAddon(addonPath) {
    currentPreviewPath = addonPath;

    try {
        const result = await api('/addons/preview', {
            method: 'POST',
            body: { path: addonPath }
        });

        if (!result.success) {
            showToast('Error previewing addon: ' + result.error, 'error');
            return;
        }

        currentPreviewData = result;

        // Update modal content
        document.getElementById('preview-modal-title').textContent = result.metadata.name || 'Preview Addon';
        document.getElementById('preview-description').textContent = result.metadata.description || '';

        // Meta info
        const metaInfo = [];
        if (result.metadata.author) metaInfo.push(`Author: ${result.metadata.author}`);
        if (result.metadata.created) {
            const date = new Date(result.metadata.created);
            metaInfo.push(`Created: ${date.toLocaleDateString()}`);
        }
        document.getElementById('preview-meta-info').innerHTML = metaInfo.length > 0
            ? `<span class="meta-item">${metaInfo.join('</span><span class="meta-item">')}</span>`
            : '';

        // Render domains list with checkboxes
        const domainsList = document.getElementById('preview-domains-list');
        domainsList.innerHTML = '';

        result.domains.forEach(domain => {
            domainsList.appendChild(renderDomainCheckbox(domain, 'preview', false));
        });

        // Track if this is a COMMANDS addon
        let isCommandsAddon = false;

        result.special_domains.forEach(domain => {
            // COMMANDS addon with hierarchical structure
            if (domain.is_commands_addon && domain.commands) {
                isCommandsAddon = true;
                domainsList.appendChild(renderCommandsAddon(domain));
            } else {
                domainsList.appendChild(renderDomainCheckbox(domain, 'preview', true));
            }
        });

        // For COMMANDS addons: hide conflicts section, change button text
        const conflictsSection = document.getElementById('preview-conflicts');
        const installBtn = document.getElementById('btn-install-addon');

        if (isCommandsAddon) {
            // COMMANDS addons use sync model - no conflict options needed
            conflictsSection.style.display = 'none';
            installBtn.textContent = 'Save Settings';
            installBtn.dataset.isCommandsAddon = 'true';
        } else {
            // Regular addons show conflict options if needed
            conflictsSection.style.display = result.has_conflicts ? 'block' : 'none';
            installBtn.textContent = 'Install Selected';
            installBtn.dataset.isCommandsAddon = 'false';
        }

        // Show modal
        document.getElementById('preview-modal').style.display = 'flex';
    } catch (err) {
        console.error('Error previewing addon:', err);
        showToast('Error previewing addon: ' + err.message, 'error');
    }
}

/**
 * Render a domain checkbox item for preview with accordion and rule-level selection
 */
function renderDomainCheckbox(domain, prefix, isSpecial) {
    const div = document.createElement('div');
    div.className = `checkbox-item-accordion ${domain.has_conflict ? 'has-conflict' : ''} ${domain.is_installed ? 'is-installed' : ''}`;
    div.dataset.domain = domain.name;

    // Show installed badge if installed by this addon, conflict badge if exists but from another source
    let statusBadge = '';
    if (domain.is_installed) {
        statusBadge = '<span class="installed-badge">installed</span>';
    } else if (domain.has_conflict) {
        statusBadge = '<span class="conflict-badge">exists</span>';
    }
    const specialBadge = isSpecial ? '<span class="special-badge">special</span>' : '';

    // Build rules list HTML with individual checkboxes
    const rules = domain.rules || [];
    const rulesHtml = rules.length > 0
        ? rules.map(r => `
            <label class="preview-rule-item">
                <input type="checkbox" name="${prefix}-rule-${domain.name}" value="${r.index}" checked data-domain="${domain.name}" data-index="${r.index}">
                <span class="rule-num">${r.index}.</span>
                <span class="rule-text">${escapeHtml(r.text)}</span>
            </label>
        `).join('')
        : '<div class="preview-rule no-rules">No rules defined</div>';

    // Select all / none buttons for rules
    const selectControls = rules.length > 0 ? `
        <div class="rule-select-controls">
            <button type="button" class="btn-link" onclick="selectAllRules('${domain.name}', true)">Select All</button>
            <span class="separator">|</span>
            <button type="button" class="btn-link" onclick="selectAllRules('${domain.name}', false)">Select None</button>
        </div>
    ` : '';

    div.innerHTML = `
        <div class="accordion-header">
            <label class="checkbox-label-wrap">
                <input type="checkbox" name="${prefix}-domain" value="${domain.name}" checked onchange="toggleDomainRules(this, '${domain.name}')">
                <span class="checkbox-label">
                    <span class="domain-name">${domain.name}</span>
                    <span class="checkbox-meta">${domain.rule_count} rule${domain.rule_count !== 1 ? 's' : ''}</span>
                    ${statusBadge}
                    ${specialBadge}
                </span>
            </label>
            <button type="button" class="accordion-toggle" onclick="toggleAccordion(this)">▼</button>
        </div>
        <div class="accordion-content" style="display: none;">
            ${selectControls}
            <div class="preview-rules-list">
                ${rulesHtml}
            </div>
        </div>
    `;

    return div;
}

/**
 * Render COMMANDS addon with command-level selection
 */
function renderCommandsAddon(domain) {
    const container = document.createElement('div');
    container.className = 'commands-addon-preview';

    // Check if any commands have conflicts
    const hasConflicts = domain.commands.some(c => c.state === 'conflict');
    const installedCount = domain.commands.filter(c => c.state === 'installed').length;

    const header = document.createElement('div');
    header.className = 'commands-addon-header';
    header.innerHTML = `
        <span class="special-badge">COMMANDS</span>
        <span class="commands-count">${domain.commands.length} command${domain.commands.length !== 1 ? 's' : ''}</span>
        ${installedCount > 0 ? `<span class="installed-badge">${installedCount} active</span>` : ''}
        ${hasConflicts ? '<span class="conflict-badge">has conflicts</span>' : ''}
        <div class="commands-select-controls">
            <button type="button" class="btn-link" onclick="selectAllCommands(true)">Select All</button>
            <span class="separator">|</span>
            <button type="button" class="btn-link" onclick="selectAllCommands(false)">Select None</button>
        </div>
    `;
    container.appendChild(header);

    // Render each command with its rules and state
    domain.commands.forEach(cmd => {
        const cmdDiv = document.createElement('div');
        cmdDiv.className = 'command-item-accordion';
        if (cmd.state === 'conflict') cmdDiv.classList.add('has-conflict');
        if (cmd.state === 'installed') cmdDiv.classList.add('is-installed');
        cmdDiv.dataset.command = cmd.name;

        const rulesHtml = cmd.rules.map(r => `
            <div class="preview-rule-item command-rule">
                <span class="rule-num">${r.index}.</span>
                <span class="rule-text">${escapeHtml(r.text)}</span>
            </div>
        `).join('');

        // Build state indicator
        let stateIndicator = '';
        if (cmd.state === 'installed') {
            stateIndicator = '<span class="cmd-state-badge installed">active</span>';
        } else if (cmd.state === 'conflict') {
            stateIndicator = `<span class="cmd-state-badge conflict" title="Owned by: ${cmd.source_pack}">conflict (${cmd.source_pack})</span>`;
        }

        // Pre-check based on backend state
        const isChecked = cmd.checked ? 'checked' : '';

        cmdDiv.innerHTML = `
            <div class="accordion-header">
                <label class="checkbox-label-wrap">
                    <input type="checkbox" name="preview-command" value="${cmd.name}" ${isChecked} data-command="${cmd.name}" data-state="${cmd.state}">
                    <span class="checkbox-label">
                        <span class="command-name">*${cmd.name.toLowerCase()}</span>
                        <span class="checkbox-meta">${cmd.rule_count} rule${cmd.rule_count !== 1 ? 's' : ''}</span>
                        ${stateIndicator}
                    </span>
                </label>
                <button type="button" class="accordion-toggle" onclick="toggleAccordion(this)">▼</button>
            </div>
            <div class="accordion-content" style="display: none;">
                <div class="preview-rules-list">
                    ${rulesHtml}
                </div>
            </div>
        `;

        container.appendChild(cmdDiv);
    });

    return container;
}

/**
 * Toggle all rules when domain checkbox changes
 */
function toggleDomainRules(domainCheckbox, domainName) {
    const isChecked = domainCheckbox.checked;
    document.querySelectorAll(`input[data-domain="${domainName}"]`).forEach(cb => {
        cb.checked = isChecked;
    });
}

/**
 * Select all or none rules for a domain
 */
function selectAllRules(domainName, selectAll) {
    document.querySelectorAll(`input[data-domain="${domainName}"]`).forEach(cb => {
        cb.checked = selectAll;
    });
    // Also update the domain checkbox
    const domainCb = document.querySelector(`input[name="preview-domain"][value="${domainName}"]`);
    if (domainCb) {
        domainCb.checked = selectAll;
    }
}

/**
 * Select all or none commands
 */
function selectAllCommands(selectAll) {
    document.querySelectorAll('input[name="preview-command"]').forEach(cb => {
        cb.checked = selectAll;
    });
}

/**
 * Toggle accordion open/closed
 */
function toggleAccordion(btn) {
    // Support both domain and command accordions
    const accordion = btn.closest('.checkbox-item-accordion, .command-item-accordion');
    if (!accordion) return;

    const content = accordion.querySelector('.accordion-content');
    const isOpen = content.style.display !== 'none';

    content.style.display = isOpen ? 'none' : 'block';
    btn.textContent = isOpen ? '▼' : '▲';
    accordion.classList.toggle('expanded', !isOpen);
}

/**
 * Escape HTML to prevent XSS
 */
function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

function closePreviewModal() {
    document.getElementById('preview-modal').style.display = 'none';
    currentPreviewPath = null;
    currentPreviewData = null;
}

/**
 * Quick install without preview
 */
async function quickInstallAddon(addonPath) {
    try {
        const result = await api('/addons/install', {
            method: 'POST',
            body: { path: addonPath, options: {} }
        });

        if (result.success) {
            showToast(`Installed ${result.installed.length} domain(s) from ${result.addon_name}`, 'success');
            await loadAddons();
        } else {
            showToast('Error installing addon: ' + (result.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        console.error('Error installing addon:', err);
        showToast('Error installing addon: ' + err.message, 'error');
    }
}

/**
 * Install addon with selected options
 */
async function installAddon() {
    if (!currentPreviewPath || !currentPreviewData) return;

    const installBtn = document.getElementById('btn-install-addon');
    const isCommandsAddon = installBtn.dataset.isCommandsAddon === 'true';

    installBtn.disabled = true;
    installBtn.textContent = isCommandsAddon ? 'Saving...' : 'Installing...';

    try {
        // Check if this is a COMMANDS addon - use sync endpoint
        if (isCommandsAddon) {
            await syncCommandsAddon();
            return;
        }

        // Regular addon installation flow
        // Collect selected domains
        const selectedDomains = [];
        document.querySelectorAll('input[name="preview-domain"]:checked').forEach(cb => {
            selectedDomains.push(cb.value);
        });

        // Collect selected rules per domain (for merge mode)
        const selectedRules = {};
        document.querySelectorAll('input[type="checkbox"][data-domain]:checked').forEach(cb => {
            const domain = cb.dataset.domain;
            const ruleIndex = parseInt(cb.dataset.index);
            if (!selectedRules[domain]) {
                selectedRules[domain] = [];
            }
            selectedRules[domain].push(ruleIndex);
        });

        // Collect selected commands (for COMMANDS addon - legacy support)
        const selectedCommands = [];
        document.querySelectorAll('input[name="preview-command"]:checked').forEach(cb => {
            selectedCommands.push(cb.value);
        });

        // Check if anything is selected
        const hasSelectedRules = Object.values(selectedRules).some(rules => rules.length > 0);
        const hasSelectedCommands = selectedCommands.length > 0;
        if (!hasSelectedRules && selectedDomains.length === 0 && !hasSelectedCommands) {
            showToast('Please select at least one domain, command, or rule to install.', 'warning');
            installBtn.disabled = false;
            installBtn.textContent = 'Install Selected';
            return;
        }

        const conflictMode = document.querySelector('input[name="conflict-mode"]:checked')?.value || 'skip';
        const activationMode = document.querySelector('input[name="activation-mode"]:checked')?.value || 'inactive';

        const options = {
            selected_domains: selectedDomains,
            selected_rules: selectedRules,
            selected_commands: selectedCommands,
            conflict_mode: conflictMode,
            overwrite: conflictMode === 'overwrite',
            merge: conflictMode === 'merge',
            activate: activationMode === 'active'
        };

        const result = await api('/addons/install', {
            method: 'POST',
            body: { path: currentPreviewPath, options: options }
        });

        if (result.success) {
            closePreviewModal();

            // Build success message
            const parts = [];
            if (result.installed && result.installed.length > 0) {
                parts.push(`${result.installed.length} domain(s) installed`);
            }
            if (result.merged && result.merged.length > 0) {
                const mergeDetails = result.merged.map(m => `${m.name} (+${m.rules_added} rules)`).join(', ');
                parts.push(`merged into: ${mergeDetails}`);
            }
            if (result.skipped && result.skipped.length > 0) {
                parts.push(`${result.skipped.length} skipped`);
            }

            const message = parts.length > 0
                ? `${result.addon_name}: ${parts.join(', ')}`
                : `${result.addon_name}: No changes made`;

            showToast(message, 'success');
            await loadAddons();
        } else {
            showToast('Error installing addon: ' + (result.error || result.errors?.join(', ') || 'Unknown error'), 'error');
        }
    } catch (err) {
        console.error('Error installing addon:', err);
        showToast('Error installing addon: ' + err.message, 'error');
    }

    installBtn.disabled = false;
    installBtn.textContent = installBtn.dataset.isCommandsAddon === 'true' ? 'Save Settings' : 'Install Selected';
}

/**
 * Sync COMMANDS addon - add checked, remove unchecked
 */
async function syncCommandsAddon() {
    const installBtn = document.getElementById('btn-install-addon');

    try {
        // Collect selected commands
        const selectedCommands = [];
        document.querySelectorAll('input[name="preview-command"]:checked').forEach(cb => {
            selectedCommands.push(cb.value);
        });

        const result = await api('/addons/sync-commands', {
            method: 'POST',
            body: {
                path: currentPreviewPath,
                selected_commands: selectedCommands
            }
        });

        if (result.success) {
            closePreviewModal();

            // Build success message
            const parts = [];
            if (result.added && result.added.length > 0) {
                parts.push(`${result.added.length} command(s) added`);
            }
            if (result.removed && result.removed.length > 0) {
                parts.push(`${result.removed.length} command(s) removed`);
            }
            if (result.renamed && result.renamed.length > 0) {
                const renameDetails = result.renamed.map(r => `${r.original} → ${r.renamed_to}`).join(', ');
                showToast(`Renamed due to conflicts: ${renameDetails}`, 'warning', 6000);
            }

            const message = parts.length > 0
                ? `${result.addon_name}: ${parts.join(', ')}`
                : `${result.addon_name}: Settings saved (${result.active_commands?.length || 0} active)`;

            showToast(message, 'success');
            await loadAddons();
        } else {
            showToast('Error syncing commands: ' + (result.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        console.error('Error syncing commands:', err);
        showToast('Error syncing commands: ' + err.message, 'error');
    }

    installBtn.disabled = false;
    installBtn.textContent = 'Save Settings';
}

/**
 * Uninstall an addon
 */
// Track current uninstall state
let currentUninstallAddon = null;
let currentUninstallData = null;

async function uninstallAddon(addonName) {
    // Open modal instead of immediate confirm
    await openUninstallModal(addonName);
}

async function openUninstallModal(addonName) {
    try {
        // Fetch preview data
        const result = await api(`/addons/${encodeURIComponent(addonName)}/preview-uninstall`);

        if (!result.success) {
            showToast('Error loading addon info: ' + (result.error || 'Unknown error'), 'error');
            return;
        }

        currentUninstallAddon = addonName;
        currentUninstallData = result;

        // Update modal content
        document.getElementById('uninstall-addon-name').textContent = `Uninstalling: ${addonName}`;

        // Domains section
        const domainsSection = document.getElementById('uninstall-domains-section');
        const domainsList = document.getElementById('uninstall-domains-list');
        if (result.domains && result.domains.length > 0) {
            domainsList.innerHTML = result.domains.map(d =>
                `<div class="uninstall-item"><span class="item-name">${d}</span></div>`
            ).join('');
            domainsSection.style.display = 'block';
        } else {
            domainsSection.style.display = 'none';
        }

        // Commands section
        const commandsSection = document.getElementById('uninstall-commands-section');
        const commandsList = document.getElementById('uninstall-commands-list');
        if (result.commands && result.commands.length > 0) {
            // Build command checkboxes
            commandsList.innerHTML = result.commands.map(cmd =>
                `<label class="checkbox-item">
                    <input type="checkbox" name="uninstall-command" value="${cmd.name}" checked>
                    <span class="item-name">${cmd.name}</span>
                    <span class="item-meta">${cmd.rule_count} rule(s)${!cmd.exists ? ' (already removed)' : ''}</span>
                </label>`
            ).join('');

            // Reset to remove_all
            document.querySelector('input[name="uninstall-command-action"][value="remove_all"]').checked = true;
            commandsList.style.display = 'none';

            // Add event listeners for radio buttons
            document.querySelectorAll('input[name="uninstall-command-action"]').forEach(radio => {
                radio.onchange = () => {
                    commandsList.style.display = radio.value === 'selected' ? 'block' : 'none';
                };
            });

            commandsSection.style.display = 'block';
        } else {
            commandsSection.style.display = 'none';
        }

        // Empty message
        const emptyMessage = document.getElementById('uninstall-empty-message');
        emptyMessage.style.display =
            (!result.domains || result.domains.length === 0) &&
            (!result.commands || result.commands.length === 0) ? 'block' : 'none';

        // Show modal
        document.getElementById('uninstall-modal').style.display = 'flex';

    } catch (err) {
        console.error('Error opening uninstall modal:', err);
        showToast('Error: ' + err.message, 'error');
    }
}

function closeUninstallModal() {
    document.getElementById('uninstall-modal').style.display = 'none';
    currentUninstallAddon = null;
    currentUninstallData = null;
}

async function confirmUninstall() {
    if (!currentUninstallAddon) return;

    const btn = document.getElementById('btn-confirm-uninstall');
    btn.disabled = true;
    btn.textContent = 'Uninstalling...';

    try {
        // Get command action
        const commandAction = document.querySelector('input[name="uninstall-command-action"]:checked')?.value || 'remove_all';

        // Get selected commands if action is 'selected'
        let commandsToRemove = null;
        if (commandAction === 'selected') {
            commandsToRemove = [];
            document.querySelectorAll('input[name="uninstall-command"]:checked').forEach(cb => {
                commandsToRemove.push(cb.value);
            });
        }

        const result = await api(`/addons/${encodeURIComponent(currentUninstallAddon)}`, {
            method: 'DELETE',
            body: {
                command_action: commandAction,
                commands_to_remove: commandsToRemove
            }
        });

        if (result.success) {
            closeUninstallModal();

            const parts = [];
            if (result.removed && result.removed.length > 0) {
                parts.push(`${result.removed.length} domain(s)`);
            }
            if (result.removed_commands && result.removed_commands.length > 0) {
                parts.push(`${result.removed_commands.length} command(s) removed`);
            }
            if (result.kept_commands && result.kept_commands.length > 0) {
                parts.push(`${result.kept_commands.length} command(s) kept`);
            }
            const removedText = parts.length > 0 ? parts.join(', ') : 'Registry entry removed';
            showToast(`Uninstalled "${currentUninstallAddon}". ${removedText}`, 'success');
            await loadAddons();
        } else {
            showToast('Error uninstalling addon: ' + (result.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        console.error('Error uninstalling addon:', err);
        showToast('Error uninstalling addon: ' + err.message, 'error');
    } finally {
        btn.disabled = false;
        btn.textContent = 'Uninstall';
    }
}

// ---- Export Functions ----

async function openExportModal() {
    document.getElementById('export-name').value = '';
    document.getElementById('export-description').value = '';
    document.getElementById('export-author').value = '';
    document.getElementById('export-tags').value = '';

    const domainsList = document.getElementById('export-domains-list');
    domainsList.innerHTML = '<div class="loading">Loading domains...</div>';

    document.getElementById('export-modal').style.display = 'flex';

    try {
        const result = await api('/addons/exportable');

        if (!result.success) {
            domainsList.innerHTML = `<div class="error">${result.error}</div>`;
            return;
        }

        if (result.domains.length === 0) {
            domainsList.innerHTML = '<div class="no-domains">No domains available to export.</div>';
            return;
        }

        domainsList.innerHTML = '';
        result.domains.forEach(domain => {
            const div = document.createElement('label');
            div.className = `checkbox-item ${domain.is_special ? 'special' : ''}`;

            const specialBadge = domain.is_special ? '<span class="special-badge">core</span>' : '';
            const stateBadge = domain.state === 'active'
                ? '<span class="state-badge active">active</span>'
                : '<span class="state-badge">inactive</span>';

            div.innerHTML = `
                <input type="checkbox" name="export-domain" value="${domain.name}">
                <span class="checkbox-label">
                    ${domain.name}
                    <span class="checkbox-meta">${domain.rule_count} rule${domain.rule_count !== 1 ? 's' : ''}</span>
                    ${stateBadge}
                    ${specialBadge}
                </span>
            `;

            domainsList.appendChild(div);
        });
    } catch (err) {
        console.error('Error loading exportable domains:', err);
        domainsList.innerHTML = '<div class="error">Error loading domains</div>';
    }
}

function closeExportModal() {
    document.getElementById('export-modal').style.display = 'none';
}

async function exportAddon() {
    const name = document.getElementById('export-name').value.trim();
    const description = document.getElementById('export-description').value.trim();
    const author = document.getElementById('export-author').value.trim();
    const tagsInput = document.getElementById('export-tags').value.trim();

    if (!name) {
        showToast('Please enter an addon name.', 'warning');
        return;
    }

    const selectedDomains = [];
    document.querySelectorAll('input[name="export-domain"]:checked').forEach(cb => {
        selectedDomains.push(cb.value);
    });

    if (selectedDomains.length === 0) {
        showToast('Please select at least one domain to export.', 'warning');
        return;
    }

    const exportBtn = document.getElementById('btn-export-addon');
    exportBtn.disabled = true;
    exportBtn.textContent = 'Exporting...';

    try {
        const tags = tagsInput ? tagsInput.split(',').map(t => t.trim()).filter(t => t) : [];

        const result = await api('/addons/export', {
            method: 'POST',
            body: {
                domains: selectedDomains,
                options: { name, description, author, tags }
            }
        });

        if (result.success) {
            exportedAddonContent = result.content;
            exportedAddonFilename = result.filename;

            closeExportModal();
            document.getElementById('export-result-json').textContent = result.content;
            document.getElementById('export-result-modal').style.display = 'flex';
        } else {
            showToast('Error exporting addon: ' + result.error, 'error');
        }
    } catch (err) {
        console.error('Error exporting addon:', err);
        showToast('Error exporting addon: ' + err.message, 'error');
    }

    exportBtn.disabled = false;
    exportBtn.textContent = 'Export Addon';
}

function closeExportResultModal() {
    document.getElementById('export-result-modal').style.display = 'none';
    exportedAddonContent = null;
    exportedAddonFilename = null;
}

async function copyExportedAddon() {
    const btn = document.getElementById('btn-copy-export');
    try {
        await navigator.clipboard.writeText(exportedAddonContent);
        btn.textContent = 'Copied!';
        setTimeout(() => { btn.textContent = 'Copy JSON'; }, 2000);
    } catch (err) {
        console.error('Error copying:', err);
        btn.textContent = 'Failed';
        setTimeout(() => { btn.textContent = 'Copy JSON'; }, 2000);
    }
}

async function saveExportedAddon() {
    if (!exportedAddonContent || !exportedAddonFilename) return;

    const saveBtn = document.getElementById('btn-save-addon');
    saveBtn.disabled = true;
    saveBtn.textContent = 'Saving...';

    try {
        const result = await api('/addons/save', {
            method: 'POST',
            body: { content: exportedAddonContent, filename: exportedAddonFilename }
        });

        if (result.success) {
            showToast('Addon saved to your library!', 'success');
            closeExportResultModal();
            await loadAddons();
        } else {
            showToast('Error saving addon: ' + result.error, 'error');
        }
    } catch (err) {
        console.error('Error saving addon:', err);
        showToast('Error saving addon: ' + err.message, 'error');
    }

    saveBtn.disabled = false;
    saveBtn.textContent = 'Save to Library';
}

/**
 * Initialize addons functionality
 */
function initAddons() {
    const refreshBtn = document.getElementById('btn-refresh-addons');
    const exportBtn = document.getElementById('btn-open-export');

    if (refreshBtn) {
        refreshBtn.addEventListener('click', loadAddons);
    }
    if (exportBtn) {
        exportBtn.addEventListener('click', openExportModal);
    }
}

// ============================================================================
// CLEANUP / UNINSTALL FUNCTIONS
// ============================================================================

let pendingCleanupAction = null;

/**
 * Render Danger Zone section in Manage Workspaces view
 */
function renderDangerZone(activeWorkspace) {
    // Remove existing danger zone if any
    const existing = document.getElementById('danger-zone-section');
    if (existing) existing.remove();

    // Only show if there's an active workspace and we're in manage workspaces mode
    if (!activeWorkspace || !isManageWorkspacesMode) return;

    const setupCard = document.querySelector('#setup-view .card');
    if (!setupCard) return;

    const dangerZone = document.createElement('div');
    dangerZone.id = 'danger-zone-section';
    dangerZone.className = 'card danger-zone-card';
    dangerZone.style.marginTop = '24px';
    dangerZone.innerHTML = `
        <h2 class="danger-title">Danger Zone</h2>
        <p class="card-description">Disable, uninstall, or fully remove CARL from this workspace</p>

        <div class="danger-actions">
            <div class="danger-action">
                <div class="danger-info">
                    <strong>Disable CARL</strong>
                    <span>Remove hooks from settings.json. Files remain for easy re-enable.</span>
                </div>
                <button class="btn btn-small btn-warning" onclick="confirmCleanupAction('disable')">Disable</button>
            </div>

            <div class="danger-action">
                <div class="danger-info">
                    <strong>Uninstall Hooks</strong>
                    <span>Delete hook script files. Re-add from Setup tab to reinstall.</span>
                </div>
                <button class="btn btn-small btn-warning" onclick="confirmCleanupAction('uninstall')">Uninstall</button>
            </div>

            <div class="danger-action">
                <div class="danger-info">
                    <strong>Full Cleanup</strong>
                    <span>Delete .carl folder, hooks, settings entries, and DB records. Destructive!</span>
                </div>
                <button class="btn btn-small btn-danger" onclick="confirmCleanupAction('full')">Cleanup</button>
            </div>
        </div>

        <div id="cleanup-preview" class="cleanup-preview" style="display: none;">
            <!-- Populated by JS when user clicks a cleanup action -->
        </div>
    `;

    setupCard.parentNode.appendChild(dangerZone);
}

/**
 * Show cleanup confirmation with preview of what will be affected
 */
async function confirmCleanupAction(action) {
    pendingCleanupAction = action;
    const previewEl = document.getElementById('cleanup-preview');

    if (!previewEl) return;

    previewEl.innerHTML = '<div class="loading">Loading preview...</div>';
    previewEl.style.display = 'block';

    try {
        const result = await api('/cleanup/preview');

        if (!result.success) {
            previewEl.innerHTML = `<div class="error">${result.error || 'Failed to load preview'}</div>`;
            return;
        }

        const p = result.preview;
        let html = '';

        if (action === 'disable') {
            html = `
                <h4>Disable CARL - What will be removed:</h4>
                <ul>
                    ${p.carl_hooks_in_settings.length > 0
                        ? p.carl_hooks_in_settings.map(h => `<li><code>${h}</code></li>`).join('')
                        : '<li>No CARL hooks found in settings.json</li>'}
                </ul>
                <p style="font-size: 0.75rem; color: var(--text-muted); margin-top: 12px;">
                    Files will remain intact. Re-enable via Setup tab.
                </p>
            `;
        } else if (action === 'uninstall') {
            html = `
                <h4>Uninstall Hooks - What will be deleted:</h4>
                <ul>
                    ${p.hook_files.length > 0
                        ? p.hook_files.map(f => `<li><code>${f}</code></li>`).join('')
                        : '<li>No hook files found</li>'}
                </ul>
                <p style="font-size: 0.75rem; color: var(--text-muted); margin-top: 12px;">
                    .carl folder and domains will remain. Reinstall hooks via Setup tab.
                </p>
            `;
        } else if (action === 'full') {
            html = `
                <h4>⚠️ Full Cleanup - Everything will be removed:</h4>
                <ul>
                    <li><strong>Settings.json:</strong> ${p.carl_hooks_in_settings.length} hook(s)</li>
                    <li><strong>Hook files:</strong> ${p.hook_files.length} file(s)</li>
                    <li><strong>.carl folder:</strong> ${p.carl_folder_exists ? p.carl_folder_contents.join(', ') || 'empty' : 'not found'}</li>
                    <li><strong>Database:</strong> ${p.db_profile_exists ? `Profile + ${p.db_snapshots_count} snapshot(s)` : 'no profile'}</li>
                </ul>
                <p style="font-size: 0.75rem; color: var(--danger); margin-top: 12px;">
                    This action is destructive and cannot be undone!
                </p>
            `;
        }

        html += `
            <div class="cleanup-confirm-buttons">
                <button class="btn btn-small btn-secondary" onclick="cancelCleanupAction()">Cancel</button>
                <button class="btn btn-small ${action === 'full' ? 'btn-danger' : 'btn-warning'}"
                        onclick="executeCleanupAction('${action}')">
                    Confirm ${action.charAt(0).toUpperCase() + action.slice(1)}
                </button>
            </div>
        `;

        previewEl.innerHTML = html;

    } catch (err) {
        console.error('Error loading cleanup preview:', err);
        previewEl.innerHTML = `<div class="error">Error: ${err.message}</div>`;
    }
}

/**
 * Cancel cleanup action
 */
function cancelCleanupAction() {
    pendingCleanupAction = null;
    const previewEl = document.getElementById('cleanup-preview');
    if (previewEl) {
        previewEl.style.display = 'none';
        previewEl.innerHTML = '';
    }
}

/**
 * Execute the cleanup action
 */
async function executeCleanupAction(action) {
    const previewEl = document.getElementById('cleanup-preview');

    if (previewEl) {
        previewEl.innerHTML = '<div class="loading">Executing cleanup...</div>';
    }

    try {
        let endpoint;
        if (action === 'disable') {
            endpoint = '/cleanup/disable';
        } else if (action === 'uninstall') {
            endpoint = '/cleanup/uninstall';
        } else if (action === 'full') {
            endpoint = '/cleanup/full';
        }

        const result = await api(endpoint, { method: 'POST' });

        if (result.success) {
            let message = '';
            if (action === 'disable') {
                message = `Disabled ${result.removed_hooks?.length || 0} hook(s) from settings.json`;
            } else if (action === 'uninstall') {
                message = `Uninstalled ${result.uninstalled?.deleted_files?.length || 0} hook file(s)`;
            } else if (action === 'full') {
                message = 'Full cleanup complete. CARL has been removed from this workspace.';
            }

            if (previewEl) {
                previewEl.innerHTML = `
                    <div style="color: var(--success); padding: 12px;">
                        ✓ ${message}
                    </div>
                    <div class="cleanup-confirm-buttons">
                        <button class="btn btn-small btn-secondary" onclick="cancelCleanupAction()">Close</button>
                    </div>
                `;
            }

            // Refresh the UI state
            if (action === 'full') {
                // Full cleanup removes workspace - refresh to show disconnected state
                setTimeout(() => {
                    window.location.reload();
                }, 2000);
            } else {
                // Reload hooks status
                await loadOptionalHooks();
            }
        } else {
            throw new Error(result.error || 'Cleanup failed');
        }

    } catch (err) {
        console.error('Error executing cleanup:', err);
        if (previewEl) {
            previewEl.innerHTML = `
                <div class="error">Error: ${err.message}</div>
                <div class="cleanup-confirm-buttons">
                    <button class="btn btn-small btn-secondary" onclick="cancelCleanupAction()">Close</button>
                </div>
            `;
        }
    }

    pendingCleanupAction = null;
}

/**
 * Full cleanup of a specific addon hook
 */
async function cleanupAddonFull(hookName) {
    if (!confirm(`Are you sure you want to fully remove ${hookName}? This will delete the file and remove from settings.json.`)) {
        return;
    }

    try {
        const result = await api(`/cleanup/addon/${encodeURIComponent(hookName)}`, {
            method: 'POST'
        });

        if (result.success) {
            await loadOptionalHooks();
        } else {
            alert('Cleanup failed: ' + (result.error || 'Unknown error'));
        }
    } catch (err) {
        console.error('Error cleaning up addon:', err);
        alert('Error: ' + err.message);
    }
}

// =============================================
// HOOK VERSION MANAGEMENT
// =============================================

// Hook update state
let hookUpdatesAvailable = false;
let hookUpdatesInfo = [];

/**
 * Check if installed hooks need updates
 */
async function checkHookVersions() {
    try {
        const result = await api('/hooks/versions');

        if (result.success && result.updates_available) {
            hookUpdatesAvailable = true;
            hookUpdatesInfo = result.hooks_needing_update || [];
            showHookUpdateNotification(hookUpdatesInfo);
        } else {
            hookUpdatesAvailable = false;
            hookUpdatesInfo = [];
            hideHookUpdateNotification();
        }
    } catch (err) {
        console.log('Hook version check failed:', err);
        // Silently fail - don't bother user
    }
}

/**
 * Show hook update notification
 */
function showHookUpdateNotification(hooks) {
    const notification = document.getElementById('hook-update-notification');
    const hooksList = document.getElementById('hook-update-list');

    if (!notification) return;

    // Build list of outdated hooks
    let listHtml = '';
    for (const hook of hooks) {
        const name = hook.filename.replace('.py', '').replace(/-/g, ' ');
        listHtml += `<li>${name}: v${hook.installed_version || '?'} → v${hook.bundled_version}</li>`;
    }

    if (hooksList) {
        hooksList.innerHTML = listHtml;
    }

    notification.style.display = 'block';
}

/**
 * Hide hook update notification
 */
function hideHookUpdateNotification() {
    const notification = document.getElementById('hook-update-notification');
    if (notification) {
        notification.style.display = 'none';
    }
}

/**
 * Update all outdated hooks
 */
async function updateOutdatedHooks() {
    const updateBtn = document.getElementById('btn-update-hooks');
    if (updateBtn) {
        updateBtn.disabled = true;
        updateBtn.textContent = 'Updating...';
    }

    try {
        const result = await api('/hooks/update-all', { method: 'POST' });

        if (result.success) {
            const count = (result.updated || []).length;
            showToast(`Updated ${count} hook(s) successfully`, 'success');
            hideHookUpdateNotification();
            hookUpdatesAvailable = false;
            hookUpdatesInfo = [];
        } else {
            showToast('Hook update failed: ' + (result.errors?.[0]?.error || 'Unknown error'), 'error');
        }
    } catch (err) {
        console.error('Hook update error:', err);
        showToast('Hook update failed: ' + err.message, 'error');
    }

    if (updateBtn) {
        updateBtn.disabled = false;
        updateBtn.textContent = 'Update Hooks';
    }
}

/**
 * Dismiss hook update notification
 */
function dismissHookUpdate() {
    hideHookUpdateNotification();
}


// =============================================
// AUTO-UPDATE SYSTEM
// =============================================

// Update state
let updateCheckInterval = null;

/**
 * Initialize the auto-update system
 */
function initUpdates() {
    // Get DOM elements
    const updateBanner = document.getElementById('update-banner');
    const updateVersion = document.getElementById('update-version');
    const downloadBtn = document.getElementById('btn-update-download');
    const dismissBtn = document.getElementById('btn-update-dismiss');
    const applyBtn = document.getElementById('btn-update-apply');
    const progressEl = document.getElementById('update-progress');
    const progressFill = document.getElementById('update-progress-fill');
    const progressText = document.getElementById('update-progress-text');
    const readyEl = document.getElementById('update-ready');
    const actionsEl = document.querySelector('.update-actions');

    if (!updateBanner) return;

    // Check for updates on init
    checkForUpdates();

    // Periodically check (every 30 minutes)
    updateCheckInterval = setInterval(checkForUpdates, 30 * 60 * 1000);

    // Event listeners
    if (downloadBtn) {
        downloadBtn.addEventListener('click', startDownload);
    }
    if (dismissBtn) {
        dismissBtn.addEventListener('click', dismissUpdate);
    }
    if (applyBtn) {
        applyBtn.addEventListener('click', applyUpdate);
    }
}

/**
 * Check for updates from GitHub
 */
async function checkForUpdates() {
    try {
        const result = await api('/update/check', { method: 'POST' });

        if (result.available && result.download_url) {
            showUpdateBanner(result.latest_version);
        }
    } catch (err) {
        console.log('Update check failed:', err);
        // Silently fail - don't bother user with update check errors
    }
}

/**
 * Show the update available banner
 */
function showUpdateBanner(version) {
    const banner = document.getElementById('update-banner');
    const versionEl = document.getElementById('update-version');

    if (banner && versionEl) {
        versionEl.textContent = `v${version}`;
        banner.style.display = 'block';
    }
}

/**
 * Hide the update banner
 */
function hideUpdateBanner() {
    const banner = document.getElementById('update-banner');
    if (banner) {
        banner.style.display = 'none';
    }
}

/**
 * Start downloading the update
 */
async function startDownload() {
    const actionsEl = document.querySelector('.update-actions');
    const progressEl = document.getElementById('update-progress');
    const progressFill = document.getElementById('update-progress-fill');
    const progressText = document.getElementById('update-progress-text');

    // Hide download button, show progress
    if (actionsEl) actionsEl.style.display = 'none';
    if (progressEl) progressEl.style.display = 'flex';

    try {
        // Start the download
        const result = await api('/update/download', { method: 'POST' });

        if (!result.success) {
            showToast('Download failed: ' + (result.error || 'Unknown error'), 'error');
            resetUpdateUI();
            return;
        }

        // Poll for progress
        pollDownloadProgress();

    } catch (err) {
        console.error('Download error:', err);
        showToast('Download failed: ' + err.message, 'error');
        resetUpdateUI();
    }
}

/**
 * Poll for download progress
 */
async function pollDownloadProgress() {
    const progressFill = document.getElementById('update-progress-fill');
    const progressText = document.getElementById('update-progress-text');
    const progressEl = document.getElementById('update-progress');
    const readyEl = document.getElementById('update-ready');

    const poll = async () => {
        try {
            const status = await api('/update/status');

            if (status.downloading) {
                // Update progress bar
                const progress = status.download_progress || 0;
                if (progressFill) progressFill.style.width = `${progress}%`;
                if (progressText) progressText.textContent = `Downloading... ${progress}%`;

                // Continue polling
                setTimeout(poll, 500);
            } else if (status.ready_to_install) {
                // Download complete
                if (progressEl) progressEl.style.display = 'none';
                if (readyEl) readyEl.style.display = 'flex';
            } else if (status.error) {
                showToast('Download failed: ' + status.error, 'error');
                resetUpdateUI();
            } else {
                // Unknown state, keep polling briefly
                setTimeout(poll, 1000);
            }
        } catch (err) {
            console.error('Progress poll error:', err);
            setTimeout(poll, 2000);
        }
    };

    poll();
}

/**
 * Apply the downloaded update (triggers restart)
 */
async function applyUpdate() {
    const applyBtn = document.getElementById('btn-update-apply');
    if (applyBtn) {
        applyBtn.disabled = true;
        applyBtn.textContent = 'Installing...';
    }

    try {
        const result = await api('/update/apply', { method: 'POST' });

        if (result.success) {
            showToast('Update applied! Restarting...', 'success', 10000);
            // The app will close and restart automatically
        } else {
            showToast('Update failed: ' + (result.error || 'Unknown error'), 'error');
            if (applyBtn) {
                applyBtn.disabled = false;
                applyBtn.textContent = 'Install & Restart';
            }
        }
    } catch (err) {
        console.error('Apply update error:', err);
        showToast('Update failed: ' + err.message, 'error');
        if (applyBtn) {
            applyBtn.disabled = false;
            applyBtn.textContent = 'Install & Restart';
        }
    }
}

/**
 * Dismiss the update notification
 */
async function dismissUpdate() {
    hideUpdateBanner();

    try {
        await api('/update/dismiss', { method: 'POST' });
    } catch (err) {
        // Ignore errors on dismiss
    }
}

/**
 * Reset update UI to initial state
 */
function resetUpdateUI() {
    const actionsEl = document.querySelector('.update-actions');
    const progressEl = document.getElementById('update-progress');
    const readyEl = document.getElementById('update-ready');
    const progressFill = document.getElementById('update-progress-fill');

    if (actionsEl) actionsEl.style.display = 'flex';
    if (progressEl) progressEl.style.display = 'none';
    if (readyEl) readyEl.style.display = 'none';
    if (progressFill) progressFill.style.width = '0%';
}

// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
    init();
    initMainNav();
    initAddons();
    initUpdates();
});
