// =============================================
// sidepanel.js — Pidgey Assist: Orchestrator
// Wires all modules together. ~200 lines.
// =============================================
import { GEMINI_BASE, DEFAULT_MODEL, EMBEDDING_MODEL } from './sp-config.js';
import { sendToContentScript, notifyContentScript, isRestrictedUrl } from './sp-comms.js';
import { initTools } from './sp-tools.js';
import { state } from './sp-state.js';
import { initUI, setStatus, playAudioAlert, formatMessage, formatReport, addBotMessage, renderSavedMessages, showToast } from './sp-ui.js';
import { initPhoenix, activatePhoenixUI, verifyExtensionIntegrity, checkPhoenixHeartbeat } from './sp-phoenix.js';
import { initAgent } from './sp-agent.js';
import { initChat, sendMessage, runDemoCinematic } from './sp-chat.js';
import { PERSONAS } from './sp-personas.js';
import { initAnimator } from './sp-animator.js';

// ======== DOM REFS ========
const $ = id => document.getElementById(id);
const setupOverlay = $('setup-overlay');
const app = $('app');
const setupKey = $('setup-key');
const setupSave = $('setup-save');
const settingsPanel = $('settings-panel');
const settingsKey = $('settings-key');
const settingsSave = $('settings-save');
const settingsModel = $('settings-model');
const settingsImageModel = $('settings-image-model');
const settingsBaseUrl = $('settings-base-url');
const settingsTavilyKey = $('settings-tavily-key');
const settingsCryptoKey = $('settings-crypto-key');
const settingsSavedMsg = $('settings-saved-msg');
const backpackPanel = $('backpack-panel');
const backpackFiles = $('backpack-files');
const btnSettings = $('btn-settings-sidebar') || $('btn-settings');
const btnTutorial = $('btn-tour-sidebar') || $('btn-tutorial-sidebar') || $('btn-tutorial');
const btnSidebarChat = $('btn-sidebar-chat');
const btnClear = $('btn-clear-sidebar') || $('btn-clear');
const btnSend = $('btn-send');
const btnMic = $('btn-mic') || $('btn-mic-sidebar');
const btnBackpack = $('btn-backpack-sidebar') || $('btn-backpack');

const btnOpenDownloads = $('btn-open-downloads');
const backpackSearch = $('backpack-search');
const backpackSort = $('backpack-sort');
const backpackBreadcrumb = $('backpack-breadcrumb');
const backpackFolders = $('backpack-folders');
const backpackEmpty = $('backpack-empty');
const backpackStats = $('backpack-stats');
const btnBackpackGrid = $('btn-backpack-grid');
const btnBackpackList = $('btn-backpack-list');
const btnNewFolder = $('btn-new-folder');
let bpViewMode = 'grid';
let bpCurrentFolder = '';
let bpSortBy = 'newest';
const chatInput = $('chat-input');
const btnVision = $('btn-vision');
const messagesEl = $('messages');
const statusText = $('status-text');
const setupStatus = $('setup-status');
const phoenixStatus = $('phoenix-status');
const phoenixVerify = $('phoenix-verify');
const settingsPhoenixCode = $('settings-phoenix-code');
const btnUpgrade = $('btn-upgrade');
const mascotBadge = $('mascot-badge');
const phoenixModeTag = $('phoenix-mode-tag');
const btnAgent = $('btn-agent-sidebar') || $('btn-agent');
const agentPanel = $('agent-panel');
const agentGoal = $('agent-goal');
const btnLaunchAgent = $('btn-launch-agent');
const agentProgress = $('agent-progress');
const agentSteps = $('agent-steps');
const btnStopAgent = $('btn-stop-agent');
const mascotImg = $('mascot-img');
// Alternative provider fields
const settingsOpenrouterKey = $('settings-openrouter-key');
const settingsOpenrouterModel = $('settings-openrouter-model');
const settingsOpenaiKey = $('settings-openai-key');
const settingsOpenaiModel = $('settings-openai-model');
const settingsAnthropicKey = $('settings-anthropic-key');
const settingsAnthropicModel = $('settings-anthropic-model');
const btnSaveOpenrouter = $('btn-save-openrouter');
const btnSaveOpenai = $('btn-save-openai');
const btnSaveAnthropic = $('btn-save-anthropic');
const activeProviderBadge = $('active-provider-badge');
const activeModelTag = $('active-model-tag');
const personaDisplay = $('persona-display');
const btnPersonas = $('btn-personas-sidebar') || $('btn-personas');
const btnProviders = $('btn-providers-sidebar') || $('btn-providers');
const personasPanel = $('personas-panel');
const providersPanel = $('providers-panel');
const providersSavedMsg = $('providers-saved-msg');
const settingsEmail = $('settings-email');
const settingsConfirmActions = $('settings-confirm-actions');
const settingsTheme = $('settings-theme');
const btnSavePreferences = $('btn-save-preferences');

// ======== MODULE INIT ========
initUI({ messagesEl, statusText, chatInput }, () => sendMessage);
initPhoenix({ mascotBadge, mascotImg, phoenixModeTag, btnAgent, agentPanel, phoenixStatus, settingsPhoenixCode });
initAgent({ agentSteps, agentProgress, btnLaunchAgent, agentGoal, btnAgent, agentPanel, btnStopAgent, settingsPanel, backpackPanel });
initChat({ chatInput, messagesEl });
initTools(state, { setStatus, playAudioAlert, formatMessage, formatReport, addBotMessage });
initAnimator();

// ======== INIT ========
async function init() {
    verifyExtensionIntegrity();

    const sync = await chrome.storage.local.get(['pidgeyApiKey', 'pidgeyModel', 'pidgeyImageModel', 'pidgeyNestEgg', 'pidgeyBaseUrl', 'pidgeyPhoenixCode', 'pidgeyTavilyKey', 'pidgeyCryptoKey', 'pidgeyProvider', 'pidgeyAltKey', 'pidgeyAltModel', 'pidgeyPersona', 'pidgeyEmail', 'pidgeyConfirmActions', 'pidgeyVisibleTabs', 'pidgeyAutoVision', 'pidgeyVoiceChat', 'pidgeyVoiceVolume', 'pidgeyVoiceURI', 'pidgeyMultiTab', 'pidgeyShowHints', 'pidgeyTheme']);
    const local = await chrome.storage.local.get(['pidgeyChatHistory', 'pidgeyTokensUsed', 'pidgeyDeviceId', 'pidgeyFirstTimeTour']);

    // Generate or retrieve Device ID for secure key validation
    let deviceId = local.pidgeyDeviceId;
    if (!deviceId) {
        const arr = new Uint32Array(3);
        crypto.getRandomValues(arr);
        deviceId = 'pid_' + Array.from(arr).map(n => n.toString(36)).join('') + Date.now().toString(36);
        await chrome.storage.local.set({ pidgeyDeviceId: deviceId });
    }
    state.pidgeyDeviceId = deviceId;

    state.tokensUsed = local.pidgeyTokensUsed || 0;
    const tokenDisplay = document.getElementById('token-counter-display');
    if (tokenDisplay) tokenDisplay.textContent = state.tokensUsed.toLocaleString();

    if (sync.pidgeyPersona && PERSONAS[sync.pidgeyPersona]) {
        state.activePersona = sync.pidgeyPersona;
        const p = PERSONAS[sync.pidgeyPersona];
        personaDisplay.textContent = `${p.icon} ${p.name}`;
    }

    window.updatePersonaUI = function () {
        document.querySelectorAll('.trader-only-ui').forEach(el => el.classList.toggle('hidden', state.activePersona !== 'trader'));
        document.querySelectorAll('.growth-only-ui').forEach(el => el.classList.toggle('hidden', state.activePersona !== 'growth'));
        document.querySelectorAll('.homestead-only-ui').forEach(el => el.classList.toggle('hidden', state.activePersona !== 'homestead'));
        document.querySelectorAll('.reseller-only-ui').forEach(el => el.classList.toggle('hidden', state.activePersona !== 'reseller'));
        document.querySelectorAll('.assist-only-ui').forEach(el => el.classList.toggle('hidden', state.activePersona !== 'assist'));
        
        const sidebarPersonaIcon = document.getElementById('sidebar-persona-icon');
        if (sidebarPersonaIcon && PERSONAS[state.activePersona]) {
            sidebarPersonaIcon.textContent = PERSONAS[state.activePersona].icon;
        }
    };
    updatePersonaUI();

    if (sync.pidgeyNestEgg) { try { Object.assign(state.nestEggMemory, JSON.parse(sync.pidgeyNestEgg)); } catch { } }

    // Restore alternative provider if saved
    if (sync.pidgeyProvider && sync.pidgeyProvider !== 'gemini') {
        const providerUrls = { openrouter: 'https://openrouter.ai/api/v1', openai: 'https://api.openai.com/v1', anthropic: '__anthropic__' };
        state.config.baseUrl = providerUrls[sync.pidgeyProvider] || '';
        state.config.apiKey = sync.pidgeyAltKey || sync.pidgeyApiKey || '';
        state.config.model = sync.pidgeyAltModel || state.config.model;
        state.config.provider = sync.pidgeyProvider;
        updateProviderBadge(sync.pidgeyProvider, sync.pidgeyAltModel);
        if (sync.pidgeyProvider === 'openrouter' && settingsOpenrouterKey && sync.pidgeyAltKey) {
            settingsOpenrouterKey.value = sync.pidgeyAltKey;
            if (settingsOpenrouterModel) settingsOpenrouterModel.value = sync.pidgeyAltModel || '';
        } else if (sync.pidgeyProvider === 'openai' && settingsOpenaiKey && sync.pidgeyAltKey) {
            settingsOpenaiKey.value = sync.pidgeyAltKey;
            if (settingsOpenaiModel) settingsOpenaiModel.value = sync.pidgeyAltModel || '';
        } else if (sync.pidgeyProvider === 'anthropic' && settingsAnthropicKey && sync.pidgeyAltKey) {
            settingsAnthropicKey.value = sync.pidgeyAltKey;
            if (settingsAnthropicModel) settingsAnthropicModel.value = sync.pidgeyAltModel || '';
        }
    }

    if (sync.pidgeyPhoenixCode) {
        settingsPhoenixCode.value = sync.pidgeyPhoenixCode;
        const hbResult = await checkPhoenixHeartbeat(sync.pidgeyPhoenixCode);
        if (hbResult === 'network_error') {
            const cached = await chrome.storage.local.get(['pidgeyPhoenixMode']);
            if (cached.pidgeyPhoenixMode) activatePhoenixUI();
        }
    }

    // Deprecated model migration — auto-upgrade stale stored models
    const DEPRECATED_MODELS = ['gemini-2.0-flash-exp', 'gemini-1.5-flash', 'gemini-1.5-pro', 'gemini-pro', 'gemini-1.0-pro'];
    const CURRENT_DEFAULT = DEFAULT_MODEL;

    if (sync.pidgeyApiKey || sync.pidgeyPhoenixCode) {
        state.config.apiKey = sync.pidgeyApiKey || '';
        const storedModel = sync.pidgeyModel || CURRENT_DEFAULT;
        state.config.model = DEPRECATED_MODELS.includes(storedModel) ? CURRENT_DEFAULT : storedModel;
        if (DEPRECATED_MODELS.includes(storedModel)) chrome.storage.local.set({ pidgeyModel: CURRENT_DEFAULT });
        state.config.imageModel = sync.pidgeyImageModel || 'imagen-4.0-generate-001';
        state.config.baseUrl = sync.pidgeyBaseUrl || '';
        state.config.tavilyKey = sync.pidgeyTavilyKey || '';
        state.config.cryptoKey = sync.pidgeyCryptoKey || '';
        state.config.defaultEmail = sync.pidgeyEmail || '';
        state.config.confirmBeforeAction = sync.pidgeyConfirmActions === true; // default false
        state.config.visibleResearchTabs = sync.pidgeyVisibleTabs === true;
        state.config.autoVision = sync.pidgeyAutoVision !== false; // default true
        state.config.voiceChat = sync.pidgeyVoiceChat !== false; // default true
        state.config.voiceVolume = sync.pidgeyVoiceVolume !== undefined ? sync.pidgeyVoiceVolume : 1.0;
        state.config.voiceURI = sync.pidgeyVoiceURI || '';
        state.config.multiTab = sync.pidgeyMultiTab === true;
        state.config.showHints = sync.pidgeyShowHints !== false; // default true
        state.config.theme = sync.pidgeyTheme || 'light';

        if (state.config.theme === 'dark') document.body.classList.add('dark-mode');
        if (settingsTheme) settingsTheme.value = state.config.theme;

        const cbVoiceVolume = document.getElementById('settings-voice-volume');
        if (cbVoiceVolume) cbVoiceVolume.value = state.config.voiceVolume;

        if (local.pidgeyChatHistory) {
            try {
                const saved = JSON.parse(local.pidgeyChatHistory);
                if (Array.isArray(saved) && saved.length) { state.chatHistory.push(...saved); renderSavedMessages(saved); }
            } catch { }
        }

        showApp();
        
        // Auto-run Mascot Tour on first install
        if (!local.pidgeyFirstTimeTour) {
            chrome.storage.local.set({ pidgeyFirstTimeTour: true });
            setTimeout(() => {
                runDemoCinematic();
            }, 1000);
        }
    } else { showSetup(); }

    if (window.speechSynthesis) {
        populateVoiceList();
        if (speechSynthesis.onvoiceschanged !== undefined) {
            speechSynthesis.onvoiceschanged = populateVoiceList;
        }
    }

    const urlData = await chrome.storage.local.get(['currentUrl', 'pidgeyStrikeCommand', 'pidgeyForcePersona']);
    if (urlData.currentUrl) state.currentUrl = urlData.currentUrl;
    if (urlData.pidgeyStrikeCommand) {
        const cmd = urlData.pidgeyStrikeCommand;
        const targetPersona = urlData.pidgeyForcePersona;
        chrome.storage.local.remove(['pidgeyStrikeCommand', 'pidgeyForcePersona']);
        if (state.config.apiKey) setTimeout(() => { 
            if (targetPersona && targetPersona !== state.activePersona) {
                const pBtn = document.querySelector(`.persona-option-btn[data-val="${targetPersona}"]`);
                if (pBtn) pBtn.click();
            }
            chatInput.value = cmd; btnSend.click(); 
        }, 500);
    }

    chrome.storage.onChanged.addListener(changes => {
        if (changes.currentUrl) state.currentUrl = changes.currentUrl.newValue || '';
        if (changes.pidgeyStrikeCommand?.newValue) {
            const cmd = changes.pidgeyStrikeCommand.newValue;
            const targetPersona = changes.pidgeyForcePersona?.newValue;
            chrome.storage.local.remove(['pidgeyStrikeCommand', 'pidgeyForcePersona']);
            if (state.config.apiKey) { 
                if (targetPersona && targetPersona !== state.activePersona) {
                    const pBtn = document.querySelector(`.persona-option-btn[data-val="${targetPersona}"]`);
                    if (pBtn) pBtn.click();
                }
                setTimeout(() => { chatInput.value = cmd; btnSend.click(); }, 300);
            }
        }
        if (changes.pidgeyTheme) {
            const theme = changes.pidgeyTheme.newValue || 'light';
            document.body.classList.toggle('dark-mode', theme === 'dark');
            if (settingsTheme) settingsTheme.value = theme;
        }
        if (changes.pidgeyGlobalAnnouncement) {
            const annEl = document.getElementById('global-announcement');
            if (annEl && changes.pidgeyGlobalAnnouncement.newValue) {
                annEl.textContent = changes.pidgeyGlobalAnnouncement.newValue;
                annEl.classList.remove('hidden');
            } else if (annEl) {
                annEl.classList.add('hidden');
            }
        }
    });
}

function showSetup() { setupOverlay.classList.remove('hidden'); app.classList.add('hidden'); setTimeout(() => setupKey.focus(), 100); }

function showApp() {
    setupOverlay.classList.add('hidden');
    app.classList.remove('hidden');
    
    if (settingsKey) {
        if (state.config.apiKey) {
            settingsKey.value = '••••••••' + state.config.apiKey.slice(-4);
        } else {
            settingsKey.value = '';
        }
    }
    
    if (settingsTavilyKey && state.config.tavilyKey) settingsTavilyKey.value = '••••••••' + state.config.tavilyKey.slice(-4);
    if (settingsCryptoKey && state.config.cryptoKey) settingsCryptoKey.value = '••••••••' + state.config.cryptoKey.slice(-4);
    if (settingsModel) settingsModel.value = state.config.model;
    if (settingsImageModel) settingsImageModel.value = state.config.imageModel || 'imagen-3.0-generate-002';
    if (activeModelTag) activeModelTag.textContent = state.config.model || 'Gemini';
    if (settingsBaseUrl) settingsBaseUrl.value = state.config.baseUrl || '';
    if (settingsEmail) settingsEmail.value = state.config.defaultEmail || '';
    if (settingsConfirmActions) settingsConfirmActions.checked = state.config.confirmBeforeAction;

    // Extra preferences setup
    const cbVisibleTabs = document.getElementById('settings-visible-tabs');
    if (cbVisibleTabs) cbVisibleTabs.checked = state.config.visibleResearchTabs;
    const cbAutoVision = document.getElementById('settings-auto-vision');
    if (cbAutoVision) cbAutoVision.checked = state.config.autoVision;

    // Initialize Auto-Vision state
    state.autoVision = state.config.autoVision;
    if (btnVision) {
        btnVision.classList.toggle('active', state.autoVision);
        btnVision.title = state.autoVision ? "Auto-Vision (ON)" : "Auto-Vision (OFF)";
        chatInput.placeholder = state.autoVision ? "Ask Pidgey (Vision ON)..." : "Ask Pidgey anything...";
    }
    const cbVoiceChat = document.getElementById('settings-voice-chat');
    if (cbVoiceChat) cbVoiceChat.checked = state.config.voiceChat;
    const cbMultiTab = document.getElementById('settings-multi-tab');
    if (cbMultiTab) cbMultiTab.checked = state.config.multiTab;
    const cbShowHints = document.getElementById('settings-show-hints');
    if (cbShowHints) cbShowHints.checked = state.config.showHints;

    const cbVoiceVolume = document.getElementById('settings-voice-volume');
    if (cbVoiceVolume) cbVoiceVolume.value = state.config.voiceVolume;
    const selectVoice = document.getElementById('settings-voice-select');
    if (selectVoice) selectVoice.value = state.config.voiceURI;

    if (!state.config.voiceChat && btnMic) btnMic.style.display = 'none';

    chrome.storage.local.get('pidgeyGlobalAnnouncement', (res) => {
        const annEl = document.getElementById('global-announcement');
        if (annEl && res.pidgeyGlobalAnnouncement) {
            annEl.textContent = res.pidgeyGlobalAnnouncement;
            annEl.classList.remove('hidden');
        } else if (annEl) {
            annEl.classList.add('hidden');
        }
    });

    const cbAllUrls = document.getElementById('settings-all-urls');
    const btnManagePerms = document.getElementById('btn-manage-permissions');
    if (cbAllUrls) {
        chrome.permissions.contains({ origins: ['<all_urls>'] }, (result) => {
            cbAllUrls.checked = result;
            if (result && btnManagePerms) btnManagePerms.style.display = 'none';
        });
        cbAllUrls.onchange = (e) => {
            if (e.target.checked) {
                chrome.permissions.request({ origins: ['<all_urls>'] }, (granted) => {
                    if (!granted) {
                        e.target.checked = false;
                        if (btnManagePerms) btnManagePerms.style.display = 'block';
                    } else {
                        if (btnManagePerms) btnManagePerms.style.display = 'none';
                    }
                });
            } else {
                chrome.permissions.remove({ origins: ['<all_urls>'] }, (removed) => {
                    if (!removed) e.target.checked = true;
                    if (removed && btnManagePerms) btnManagePerms.style.display = 'none';
                });
            }
        };
    }

    if (btnManagePerms) {
        btnManagePerms.onclick = () => {
            chrome.tabs.create({ url: `chrome://extensions/?id=${chrome.runtime.id}` });
        };
    }

    if (!state.chatHistory.length) {
        const p = PERSONAS[state.activePersona] || PERSONAS.assist;
        const memory = state.nestEggMemory || {};
        const userName = memory.userName || memory.user_name || "";
        const pidgeyName = memory.pidgeyName || memory.pidgey_name || p.name;
        
        let welcomeMsg = `Chirp! I'm **${pidgeyName}**! ${p.icon}\n\n`;
        if (userName) {
            welcomeMsg += `Great to see you again, **${userName}**! I'm perched and ready for our next mission.`;
        } else {
            welcomeMsg += `I'm ready to fly alongside your web journey! But before we take off... **What should I call you?** Or, **what would you like to name me?** 🐦🥚`;
        }
        
        addBotMessage(welcomeMsg);
    }
}

// ======== HINT SYSTEM ========
let currentHintTimer = null;
export function showHint(text, duration = 8000) {
    if (!state.config.showHints) return;
    const toast = document.getElementById('hint-toast');
    const hintText = document.getElementById('hint-text');
    if (!toast || !hintText) return;
    hintText.textContent = text;
    toast.classList.remove('hidden');
    toast.style.animation = 'msgIn 0.3s ease-out';
    if (currentHintTimer) clearTimeout(currentHintTimer);
    if (duration > 0) {
        currentHintTimer = setTimeout(() => toast.classList.add('hidden'), duration);
    }
}

const btnCloseHint = document.getElementById('btn-close-hint');
if (btnCloseHint) {
    btnCloseHint.onclick = () => {
        const toast = document.getElementById('hint-toast');
        if (toast) toast.classList.add('hidden');
    };
}

// Trigger initial hint
setTimeout(() => {
    if (state.config.showHints && !state.chatHistory.length) {
        showHint("You can change my personality or tweak settings using the buttons at the top! 🎭⚙️");
    }
}, 3000);

async function validateKey(key) {
    if (!key) return { success: false, error: 'Please enter a key!' };
    
    // Support Phoenix Codes for "login"
    if (key.startsWith('PHX-')) {
        const result = await checkPhoenixHeartbeat(key);
        if (result === 'valid') return { success: true };
        return { success: false, error: 'Invalid or Expired Phoenix Code' };
    }

    if (key.length < 20) return { success: false, error: 'Key looks too short (min 20 chars)' };
    
    // Auto-detect Alternative Providers (sk-proj, sk-ant, sk-or, or any sk-)
    if (key.startsWith('sk-')) {
        return { success: true, bypassed: true, altProviderDetected: true };
    }
    
    const testUrl = `https://generativelanguage.googleapis.com/v1beta/models/${DEFAULT_MODEL}:generateContent`;
    
    let lastStatus = 0;
    let lastError = '';
    
    try {
        const ctrl = new AbortController();
        const tid = setTimeout(() => ctrl.abort(), 6000); // 6s timeout
        
        // Use a cheap generateContent ping to robustly validate keys (bypasses /models endpoint restrictions)
        const r = await fetch(testUrl, { 
            method: 'POST',
            signal: ctrl.signal, 
            headers: { 
                'Content-Type': 'application/json',
                'x-goog-api-key': key 
            },
            body: JSON.stringify({
                contents: [{ role: 'user', parts: [{ text: "ping" }] }],
                generationConfig: { maxOutputTokens: 1 }
            })
        }); 
        clearTimeout(tid);

        if (r.ok) return { success: true }; 
        lastStatus = r.status;
        
        if (r.status === 429) return { success: true }; // Rate limited but valid key
        if (r.status === 403) lastError = 'Access Forbidden (403)';
        if (r.status === 400) lastError = 'Invalid Key Format (400)';
        if (r.status === 404) lastError = 'Model Not Found (404)';
        if (r.status === 401) lastError = 'Unauthorized/Invalid Key (401)';
    } catch (e) {
        console.error("Validation fetch failed for " + testUrl, e);
        lastError = (e.name === 'AbortError') ? 'Request Timeout' : `Network Error (${e.message})`;
    }

    // Lenient Validation Bypass: Extension environments (VPNs, specific proxy settings) 
    // can erroneously block the preflight options request or the ping. If it LOOKS like a valid key,
    // let them into the UI so they aren't completely locked out.
    if (key.startsWith('AIza') && key.length > 30) {
        console.warn(`Key validation failed with error [${lastError}], but it structurally looks like a valid Gemini API key. Allowing lenient bypass.`);
        return { success: true, bypassed: true };
    }
    
    return { success: false, error: lastError || 'Invalid Key' };
}

// ======== EVENT LISTENERS ========
setupSave.addEventListener('click', async () => {
    const key = setupKey.value.trim(); 
    if (!key) {
        if (setupStatus) { 
            setupStatus.textContent = '❌ Please enter a key, or use "Skip for now"!'; 
            setupStatus.style.color = '#fca5a5'; 
        }
        return;
    }
    if (setupStatus) { setupStatus.textContent = '🔄 Validating...'; setupStatus.style.color = '#93c5fd'; }
    setupSave.disabled = true;
    setupSave.textContent = 'Checking...';
    
    try {
        const validation = await validateKey(key);
        
        if (validation.success) {
            if (validation.altProviderDetected) {
                let provider = 'openai';
                let model = 'gpt-4o';
                if (key.startsWith('sk-ant-')) { provider = 'anthropic'; model = 'claude-3-5-sonnet-20241022'; }
                else if (key.startsWith('sk-or-')) { provider = 'openrouter'; model = 'google/gemini-2.5-flash'; }
                
                state.config.provider = provider;
                state.config.apiKey = key;
                state.config.model = model;
                const baseUrlMap = { openrouter: 'https://openrouter.ai/api/v1', openai: 'https://api.openai.com/v1', anthropic: '__anthropic__' };
                state.config.baseUrl = baseUrlMap[provider] || '';
                
                await chrome.storage.local.set({ 
                    pidgeyProvider: provider, 
                    pidgeyAltKey: key, 
                    pidgeyAltModel: model,
                    pidgeyModel: model
                });
                
                showApp();
                addBotMessage(`💡 **Custom Provider Detected:** I noticed you entered a non-Gemini key. I've automatically configured Pidgey to use it as an alternative provider! You can change this anytime securely from **Settings**.\n\nChirp! I'm perched in your sidebar and ready to help!`);
            } else if (key.startsWith('PHX-')) {
                await chrome.storage.local.set({ pidgeyPhoenixCode: key, pidgeyPhoenixMode: true });
                showApp();
                addBotMessage(`🔥 **Welcome back, Phoenix!**\n\nI've unlocked your advanced capabilities. To start chatting, please go to **Settings (⚙️)** and add a free Gemini API key to power my brain!`);
            } else {
                state.config.apiKey = key;
                
                // Ensure model is set before saving to avoid Chrome Storage undefined errors
                if (!state.config.model || state.config.model === 'gemini-2.5-flash') {
                    state.config.model = DEFAULT_MODEL;
                }
                
                await chrome.storage.local.set({ pidgeyApiKey: key, pidgeyModel: state.config.model });
                showApp();
                const p = PERSONAS[state.activePersona] || PERSONAS.assist;
                let intro = `Chirp! I'm ${p.name}! ${p.icon}\n\nI'm now perched in your sidebar. Ask me anything!`;
                if (validation.bypassed) intro = `⚠️ **Note:** I've allowed entry via Lenient Bypass. If I cannot generate text, please double-check your Gemini API key's "Generative Language API" permissions in Google AI Studio.\n\n` + intro;
                addBotMessage(intro);
            }
        } else {
            console.error("Validation failed:", validation.error);
            setupKey.style.borderColor = '#ef4444'; 
            if (setupStatus) { 
                setupStatus.textContent = `❌ ${validation.error}`; 
                setupStatus.style.color = '#fca5a5';
            }
            
            setTimeout(() => { 
                setupKey.style.borderColor = ''; 
                if (setupStatus) { setupStatus.textContent = ''; }
            }, 6000);
        }
    } catch (err) {
        console.error("Validation error:", err);
        if (setupStatus) { setupStatus.textContent = '❌ System Error'; setupStatus.style.color = '#fca5a5'; }
    } finally {
        setupSave.disabled = false;
        setupSave.textContent = 'Save & Fly!';
    }
});
setupKey.addEventListener('keydown', e => { if (e.key === 'Enter') setupSave.click(); });

const btnSkipSetup = $('btn-skip-setup');
if (btnSkipSetup) {
    btnSkipSetup.addEventListener('click', () => {
        showApp();
        addBotMessage(`🐣 **Welcome to Pidgey (Preview Mode)**\n\nYou're currently looking around without an API key! You can explore the UI and tools, but I won't have a brain to reply to your messages or run actions until you give me a Gemini API key.\n\nReady to hatch me? Head over to **Settings (⚙️)** in the sidebar when you have your key!`);
    });
}

const btnEmergencyReset = $('btn-emergency-reset');
if (btnEmergencyReset) {
    btnEmergencyReset.addEventListener('click', async () => {
        const userInput = prompt("🚨 WARNING: This will clear ALL your Pidgey settings, keys, and chat history.\n\nType 'RESET' to confirm.");
        if (userInput === "RESET") {
            await chrome.storage.local.clear();
            await chrome.storage.local.clear();
            window.location.reload();
        } else if (userInput !== null) {
            alert("Reset cancelled: You did not type 'RESET'.");
        }
    });
}

if (btnVision) {
    btnVision.addEventListener('click', () => {
        state.autoVision = !state.autoVision;
        state.config.autoVision = state.autoVision;
        chrome.storage.local.set({ pidgeyAutoVision: state.autoVision });
        btnVision.classList.toggle('active', state.autoVision);
        btnVision.title = state.autoVision ? "Auto-Vision (ON)" : "Auto-Vision (OFF)";
        chatInput.placeholder = state.autoVision ? "Ask Pidgey (Vision ON)..." : "Ask Pidgey anything...";
        
        const cbAutoVision = document.getElementById('settings-auto-vision');
        if (cbAutoVision) cbAutoVision.checked = state.autoVision;
    });
}

btnSettings.addEventListener('click', () => {
    if (backpackPanel) backpackPanel.classList.add('hidden');
    if (personasPanel) personasPanel.classList.add('hidden');
    if (providersPanel) providersPanel.classList.add('hidden');
    if (agentPanel) agentPanel.classList.add('hidden');
    const isHidden = settingsPanel.classList.toggle('hidden');
    if (settingsModel) settingsModel.value = state.config.model;
    updateSidebarActive(isHidden ? btnSidebarChat : btnSettings);
});

if (btnTutorial) {
    btnTutorial.addEventListener('click', runDemoCinematic);
}

if (btnUpgrade) {
    btnUpgrade.addEventListener('click', () => {
        chrome.tabs.create({ url: 'https://pidgeyassist.com/#plans' });
    });
}

const btnResetTokens = document.getElementById('btn-reset-tokens');
if (btnResetTokens) {
    btnResetTokens.addEventListener('click', async () => {
        state.tokensUsed = 0;
        await chrome.storage.local.set({ pidgeyTokensUsed: 0 });
        const counter = document.getElementById('token-counter-display');
        if (counter) counter.textContent = '0';
    });
}

if (phoenixVerify) {
    phoenixVerify.addEventListener('click', async () => {
        const code = settingsPhoenixCode.value.trim().toUpperCase(); if (!code) return;
        settingsPhoenixCode.value = code; phoenixVerify.textContent = 'Wait...';
        const result = await checkPhoenixHeartbeat(code);
        if (result === 'valid') { await chrome.storage.local.set({ pidgeyPhoenixCode: code }); phoenixVerify.textContent = 'Verified!'; setTimeout(() => phoenixVerify.textContent = 'Verify', 2000); }
        else if (result === 'network_error') { phoenixVerify.textContent = 'Server Error'; setTimeout(() => phoenixVerify.textContent = 'Verify', 3000); }
        else { phoenixVerify.textContent = 'Failed'; setTimeout(() => phoenixVerify.textContent = 'Verify', 2000); settingsPhoenixCode.value = ''; settingsPhoenixCode.placeholder = 'Invalid or Expired Code'; }
    });
}

if (btnBackpack) {
    btnBackpack.addEventListener('click', async () => {
        const stored = await chrome.storage.local.get(['pidgeyPhoenixMode']);
        if (!stored.pidgeyPhoenixMode) { settingsPanel.classList.remove('hidden'); if (personasPanel) personasPanel.classList.add('hidden'); backpackPanel.classList.add('hidden'); addBotMessage("🔒 **Phoenix Mode Required**\n\nThe Pidgey Backpack requires a Pro subscription. Link your account in **Settings**!"); updateSidebarActive(btnSettings); return; }
        settingsPanel.classList.add('hidden'); if (personasPanel) personasPanel.classList.add('hidden'); if (providersPanel) providersPanel.classList.add('hidden'); if (agentPanel) agentPanel.classList.add('hidden');
        const isHidden = backpackPanel.classList.toggle('hidden');
        if (!isHidden) loadBackpackFiles();
        updateSidebarActive(isHidden ? btnSidebarChat : btnBackpack);
    });
}

if (btnOpenDownloads) btnOpenDownloads.addEventListener('click', () => {
    try {
        chrome.tabs.create({ url: 'chrome://downloads/' });
    } catch {
        addBotMessage('📥 Open **chrome://downloads** to view your files.');
    }
});

const btnRateUs = document.getElementById('btn-rate-us-sidebar');
if (btnRateUs) {
    btnRateUs.addEventListener('click', () => {
        chrome.tabs.create({ url: `https://chromewebstore.google.com/detail/pfelaodomfjoefocaehllidonjemffpa/reviews?utm_source=item-share-cb` });
    });
}



messagesEl.addEventListener('click', () => { settingsPanel.classList.add('hidden'); if (backpackPanel) backpackPanel.classList.add('hidden'); if (personasPanel) personasPanel.classList.add('hidden'); if (providersPanel) providersPanel.classList.add('hidden'); });

chrome.runtime.onMessage.addListener(msg => {
    if (msg.type === 'PIDGEY_MONITOR_ALERT') { playAudioAlert('action'); addBotMessage(`🚨 **Sniper Bird Alert!**\n\nTarget met condition:\n\n> ${msg.message}`); }
});

function bpFileType(name) {
    const ext = (name || '').split('.').pop().toLowerCase();
    const map = { md:'doc', txt:'doc', csv:'sheet', json:'data', html:'web', htm:'web', xml:'data',
        png:'image', jpg:'image', jpeg:'image', gif:'image', webp:'image', svg:'image', bmp:'image',
        pdf:'pdf', zip:'archive', rar:'archive', '7z':'archive',
        js:'code', ts:'code', py:'code', css:'code', scss:'code' };
    return map[ext] || 'file';
}
function bpFileIcon(type) {
    const icons = { doc:'📄', sheet:'📊', data:'📋', web:'🌐', image:'🖼️', pdf:'📕', archive:'📦', code:'💻', file:'📎' };
    return icons[type] || '📎';
}
function bpFileColor(type) {
    const colors = { doc:'#3b82f6', sheet:'#10b981', data:'#f59e0b', web:'#8b5cf6', image:'#ec4899', pdf:'#ef4444', archive:'#6366f1', code:'#06b6d4', file:'#64748b' };
    return colors[type] || '#64748b';
}
function bpFormatSize(bytes) {
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
    return (bytes / 1048576).toFixed(1) + ' MB';
}

function bpOpenFile(file) {
    const w = window.open('about:blank');
    if (!w) return;
    w.document.body.style.margin = '0';
    if (file.content && typeof file.content === 'string') {
        if (file.content.startsWith('data:image/')) {
            w.document.body.style.cssText = 'margin:0;background:#000;display:flex;justify-content:center;align-items:center;height:100vh;';
            const img = w.document.createElement('img');
            img.src = file.content;
            img.style.cssText = 'max-width:100%;max-height:100vh;object-fit:contain;';
            w.document.body.appendChild(img);
        } else if (file.filename && (file.filename.endsWith('.md') || file.filename.endsWith('.txt'))) {
            const reportTitle = file.filename.replace(/\.(md|txt)$/i, '').replace(/[_-]/g, ' ');
            const reportHtml = formatReport(file.content, reportTitle);
            w.document.open(); w.document.write(reportHtml); w.document.close();
        } else {
            const iframe = w.document.createElement('iframe');
            iframe.sandbox = 'allow-scripts';
            iframe.srcdoc = file.content;
            iframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;';
            w.document.body.appendChild(iframe);
        }
    } else {
        const iframe = w.document.createElement('iframe');
        iframe.sandbox = 'allow-scripts';
        iframe.srcdoc = typeof file.content === 'object' ? JSON.stringify(file.content, null, 2) : String(file.content);
        iframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;';
        w.document.body.appendChild(iframe);
    }
}

function bpDownloadFile(file) {
    let content = file.content;
    let mimeType = 'text/plain';
    
    if (typeof content === 'string' && content.startsWith('data:')) {
        const a = document.createElement('a');
        a.href = content;
        a.download = file.filename;
        a.click();
        return;
    }
    
    const ext = file.filename.toLowerCase();

    // If it's a PDF, we can't just blob raw text. We need to render it as HTML and trigger the browser's native PDF printer.
    if (ext.endsWith('.pdf')) {
        const w = window.open('about:blank');
        if (!w) return;
        const reportTitle = file.filename.replace(/\.(pdf|md|txt|doc)$/i, '').replace(/[_-]/g, ' ');
        let reportHtml = content;
        if (!content.includes('<!DOCTYPE html>')) {
             reportHtml = formatReport(content, reportTitle);
        }
        w.document.open(); 
        w.document.write(reportHtml); 
        w.document.close();
        w.document.title = file.filename;
        setTimeout(() => { w.print(); }, 500);
        return;
    }

    if (ext.endsWith('.csv')) mimeType = 'text/csv';
    else if (ext.endsWith('.json')) mimeType = 'application/json';
    else if (ext.endsWith('.html')) mimeType = 'text/html';
    else if (ext.endsWith('.md')) mimeType = 'text/markdown';
    else if (ext.endsWith('.doc')) mimeType = 'application/msword';

    const blob = new Blob([content], { type: mimeType });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = file.filename;
    a.click();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
}
function bpCreateCard(file) {
    const type = file.type;
    const icon = bpFileIcon(type);
    const color = bpFileColor(type);
    const card = document.createElement('div');
    card.dataset.fileId = file.id;
    card.dataset.folder = file.folder || '';
    card.draggable = true;

    if (bpViewMode === 'grid') {
        card.style.cssText = 'background:white;border-radius:10px;border:2px solid #e2e8f0;padding:10px;cursor:pointer;transition:all 0.2s;position:relative;overflow:hidden;';
        card.onmouseenter = () => { card.style.borderColor = color; card.style.transform = 'translateY(-2px)'; card.style.boxShadow = '0 4px 12px rgba(0,0,0,0.08)'; };
        card.onmouseleave = () => { card.style.borderColor = '#e2e8f0'; card.style.transform = ''; card.style.boxShadow = ''; };

        const preview = document.createElement('div');
        preview.style.cssText = `width:100%;height:52px;border-radius:6px;display:flex;align-items:center;justify-content:center;margin-bottom:6px;font-size:24px;background:${color}15;`;
        if (type === 'image' && file.content && file.content.startsWith('data:image/')) {
            const thumb = document.createElement('img');
            thumb.src = file.content;
            thumb.style.cssText = 'width:100%;height:100%;object-fit:cover;border-radius:6px;';
            preview.innerHTML = '';
            preview.appendChild(thumb);
        } else {
            preview.textContent = icon;
        }
        card.appendChild(preview);

        const nameEl = document.createElement('div');
        nameEl.style.cssText = 'font-size:10px;font-weight:800;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
        nameEl.textContent = file.filename;
        nameEl.title = file.filename;
        card.appendChild(nameEl);

        const meta = document.createElement('div');
        meta.style.cssText = 'display:flex;justify-content:space-between;align-items:center;margin-top:4px;';
        const badge = document.createElement('span');
        badge.style.cssText = `font-size:8px;font-weight:700;padding:1px 5px;border-radius:4px;background:${color}20;color:${color};text-transform:uppercase;`;
        badge.textContent = type;
        const sizeEl = document.createElement('span');
        sizeEl.style.cssText = 'font-size:8px;color:#94a3b8;font-weight:600;';
        sizeEl.textContent = bpFormatSize(file.size);
        meta.appendChild(badge);
        meta.appendChild(sizeEl);
        card.appendChild(meta);

        const actions = document.createElement('div');
        actions.style.cssText = 'display:flex;gap:3px;margin-top:6px;';
        const btnView = document.createElement('button');
        btnView.textContent = 'View';
        btnView.style.cssText = `flex:1;padding:3px;font-size:9px;font-weight:800;border:none;border-radius:5px;cursor:pointer;background:${color};color:white;`;
        btnView.onclick = (e) => { e.stopPropagation(); bpOpenFile(file); };
        const btnDl = document.createElement('button');
        btnDl.textContent = '⬇️';
        btnDl.title = 'Download to computer';
        btnDl.style.cssText = 'padding:3px;font-size:9px;border:none;border-radius:5px;cursor:pointer;background:#f1f5f9;color:#333;margin:0 1px;';
        btnDl.onclick = (e) => { e.stopPropagation(); bpDownloadFile(file); };
        
        const btnDel = document.createElement('button');
        btnDel.textContent = 'Del';
        btnDel.style.cssText = 'padding:3px 6px;font-size:9px;font-weight:800;border:none;border-radius:5px;cursor:pointer;background:#fee2e2;color:#dc2626;';
        btnDel.onclick = async (e) => {
            e.stopPropagation();
            await chrome.storage.local.remove(file.id);
            if (file.folder) await chrome.storage.local.remove('_meta_' + file.filename);
            loadBackpackFiles();
        };
        actions.appendChild(btnView);
        actions.appendChild(btnDl);
        actions.appendChild(btnDel);
        card.appendChild(actions);
    } else {
        card.style.cssText = 'display:flex;align-items:center;gap:8px;padding:7px 10px;background:white;border-radius:8px;border:1px solid #e2e8f0;cursor:pointer;transition:all 0.15s;';
        card.onmouseenter = () => { card.style.background = '#f8fafc'; card.style.borderColor = color; };
        card.onmouseleave = () => { card.style.background = 'white'; card.style.borderColor = '#e2e8f0'; };

        const iconEl = document.createElement('span');
        iconEl.style.cssText = `font-size:16px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:6px;background:${color}15;flex-shrink:0;`;
        iconEl.textContent = icon;
        card.appendChild(iconEl);

        const info = document.createElement('div');
        info.style.cssText = 'flex:1;min-width:0;';
        const nameRow = document.createElement('div');
        nameRow.style.cssText = 'font-size:10px;font-weight:800;color:#1e293b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
        nameRow.textContent = file.filename;
        nameRow.title = file.filename;
        const detailRow = document.createElement('div');
        detailRow.style.cssText = 'font-size:8px;color:#94a3b8;font-weight:600;margin-top:1px;';
        detailRow.textContent = `${type.toUpperCase()} • ${bpFormatSize(file.size)}`;
        info.appendChild(nameRow);
        info.appendChild(detailRow);
        card.appendChild(info);

        const btns = document.createElement('div');
        btns.style.cssText = 'display:flex;gap:3px;flex-shrink:0;';
        const bView = document.createElement('button');
        bView.textContent = 'View';
        bView.style.cssText = `padding:3px 7px;font-size:9px;font-weight:800;border:none;border-radius:5px;cursor:pointer;background:${color};color:white;`;
        bView.onclick = (e) => { e.stopPropagation(); bpOpenFile(file); };
        const bDl = document.createElement('button');
        bDl.textContent = '⬇️';
        bDl.title = 'Download';
        bDl.style.cssText = 'padding:3px;font-size:9px;border:none;border-radius:5px;cursor:pointer;background:#f1f5f9;color:#333;margin:0 1px;';
        bDl.onclick = (e) => { e.stopPropagation(); bpDownloadFile(file); };
        
        const bDel = document.createElement('button');
        bDel.textContent = 'Del';
        bDel.style.cssText = 'padding:3px 7px;font-size:9px;font-weight:800;border:none;border-radius:5px;cursor:pointer;background:#fee2e2;color:#dc2626;';
        bDel.onclick = async (e) => {
            e.stopPropagation();
            await chrome.storage.local.remove(file.id);
            if (file.folder) await chrome.storage.local.remove('_meta_' + file.filename);
            loadBackpackFiles();
        };
        btns.appendChild(bView);
        btns.appendChild(bDl);
        btns.appendChild(bDel);
        card.appendChild(btns);
    }

    card.addEventListener('dragstart', (e) => {
        e.dataTransfer.setData('text/plain', file.id);
        e.dataTransfer.effectAllowed = 'move';
        card.style.opacity = '0.5';
    });
    card.addEventListener('dragend', () => { card.style.opacity = '1'; });
    card.addEventListener('dblclick', () => bpOpenFile(file));
    return card;
}

function bpRenderFolders(folders) {
    if (!backpackFolders) return;
    backpackFolders.innerHTML = '';
    folders.forEach(f => {
        const pill = document.createElement('button');
        pill.dataset.folder = f;
        const isActive = bpCurrentFolder === f;
        pill.style.cssText = `padding:4px 10px;border-radius:6px;font-size:9px;font-weight:800;cursor:pointer;white-space:nowrap;border:1px solid ${isActive ? '#0f766e' : '#e2e8f0'};background:${isActive ? '#ccfbf1' : 'white'};color:${isActive ? '#0f766e' : '#475569'};transition:all 0.15s;`;
        pill.textContent = '📁 ' + f;
        pill.onclick = () => { bpCurrentFolder = f; loadBackpackFiles(); };
        pill.addEventListener('dragover', (e) => { e.preventDefault(); pill.style.background = '#ccfbf1'; pill.style.borderColor = '#0f766e'; });
        pill.addEventListener('dragleave', () => { pill.style.background = isActive ? '#ccfbf1' : 'white'; pill.style.borderColor = isActive ? '#0f766e' : '#e2e8f0'; });
        pill.addEventListener('drop', async (e) => {
            e.preventDefault();
            const fileId = e.dataTransfer.getData('text/plain');
            if (!fileId) return;
            const fname = fileId.replace('_file_', '');
            await chrome.storage.local.set({ ['_meta_' + fname]: { folder: f, created: Date.now() } });
            loadBackpackFiles();
            showToast('Moved to ' + f);
        });
        backpackFolders.appendChild(pill);
    });
}

function bpRenderBreadcrumb() {
    if (!backpackBreadcrumb) return;
    backpackBreadcrumb.innerHTML = '';
    const root = document.createElement('span');
    root.style.cssText = 'cursor:pointer;' + (bpCurrentFolder ? '' : 'color:#134e4a;');
    root.textContent = '🏠 All Files';
    root.onclick = () => { bpCurrentFolder = ''; loadBackpackFiles(); };
    backpackBreadcrumb.appendChild(root);
    if (bpCurrentFolder) {
        const sep = document.createElement('span');
        sep.textContent = ' › ';
        sep.style.cssText = 'color:#94a3b8;margin:0 2px;';
        backpackBreadcrumb.appendChild(sep);
        const crumb = document.createElement('span');
        crumb.style.cssText = 'color:#134e4a;font-weight:800;';
        crumb.textContent = '📁 ' + bpCurrentFolder;
        backpackBreadcrumb.appendChild(crumb);
    }
}

async function loadBackpackFiles() {
    if (!backpackFiles) return;
    backpackFiles.innerHTML = '<div style="font-size:11px;color:#6b7280;text-align:center;padding:20px;">Looking in backpack...</div>';

    const allData = await chrome.storage.local.get(null);
    const folders = allData._backpack_folders || [];
    const search = backpackSearch ? backpackSearch.value.toLowerCase().trim() : '';

    let files = Object.keys(allData).filter(k => k.startsWith('_file_')).map(k => {
        const content = allData[k];
        const filename = k.replace('_file_', '');
        const meta = allData['_meta_' + filename] || {};
        const size = typeof content === 'string' ? content.length : (typeof content === 'object' ? JSON.stringify(content).length : 0);
        return { id: k, filename, content, folder: meta.folder || '', size, created: meta.created || 0, type: bpFileType(filename) };
    });

    if (backpackStats) {
        const totalSize = files.reduce((s, f) => s + f.size, 0);
        backpackStats.textContent = files.length + ' files \u2022 ' + bpFormatSize(totalSize);
    }

    files = files.filter(f => f.folder === bpCurrentFolder);
    if (search) files = files.filter(f => f.filename.toLowerCase().includes(search));

    switch (bpSortBy) {
        case 'oldest': files.sort((a, b) => a.created - b.created); break;
        case 'name': files.sort((a, b) => a.filename.localeCompare(b.filename)); break;
        case 'size': files.sort((a, b) => b.size - a.size); break;
        case 'type': files.sort((a, b) => a.type.localeCompare(b.type)); break;
        default: files.sort((a, b) => b.created - a.created);
    }

    bpRenderFolders(folders);
    bpRenderBreadcrumb();

    backpackFiles.innerHTML = '';
    if (!files.length) {
        if (backpackEmpty) backpackEmpty.style.display = 'block';
        return;
    }
    if (backpackEmpty) backpackEmpty.style.display = 'none';

    if (bpViewMode === 'grid') {
        backpackFiles.style.display = 'grid';
        backpackFiles.style.gridTemplateColumns = 'repeat(2,1fr)';
    } else {
        backpackFiles.style.display = 'flex';
        backpackFiles.style.flexDirection = 'column';
        backpackFiles.style.gridTemplateColumns = '';
    }

    files.forEach(f => backpackFiles.appendChild(bpCreateCard(f)));

    backpackFiles.addEventListener('dragover', (e) => e.preventDefault());
    backpackFiles.addEventListener('drop', async (e) => {
        e.preventDefault();
        const fileId = e.dataTransfer.getData('text/plain');
        if (!fileId || !bpCurrentFolder) return;
        const fname = fileId.replace('_file_', '');
        await chrome.storage.local.set({ ['_meta_' + fname]: { folder: bpCurrentFolder, created: Date.now() } });
        loadBackpackFiles();
    });
}

if (backpackSearch) backpackSearch.addEventListener('input', () => loadBackpackFiles());
if (backpackSort) backpackSort.addEventListener('change', () => { bpSortBy = backpackSort.value; loadBackpackFiles(); });
if (btnBackpackGrid) btnBackpackGrid.addEventListener('click', () => {
    bpViewMode = 'grid';
    if (btnBackpackGrid) { btnBackpackGrid.style.background = 'rgba(255,255,255,0.2)'; btnBackpackGrid.classList.add('bp-view-active'); }
    if (btnBackpackList) { btnBackpackList.style.background = 'rgba(255,255,255,0.08)'; btnBackpackList.classList.remove('bp-view-active'); }
    loadBackpackFiles();
});
if (btnBackpackList) btnBackpackList.addEventListener('click', () => {
    bpViewMode = 'list';
    if (btnBackpackList) { btnBackpackList.style.background = 'rgba(255,255,255,0.2)'; btnBackpackList.classList.add('bp-view-active'); }
    if (btnBackpackGrid) { btnBackpackGrid.style.background = 'rgba(255,255,255,0.08)'; btnBackpackGrid.classList.remove('bp-view-active'); }
    loadBackpackFiles();
});
if (btnNewFolder) btnNewFolder.addEventListener('click', async () => {
    const name = prompt('Folder name:');
    if (!name || !name.trim()) return;
    const allData = await chrome.storage.local.get('_backpack_folders');
    const folders = allData._backpack_folders || [];
    if (folders.includes(name.trim())) { showToast('Folder already exists'); return; }
    folders.push(name.trim());
    await chrome.storage.local.set({ _backpack_folders: folders });
    showToast('Folder created: ' + name.trim());
    loadBackpackFiles();
});

settingsSave.addEventListener('click', async () => {
    const newKey = settingsKey.value.trim(), newTav = settingsTavilyKey.value.trim(), newCryp = settingsCryptoKey ? settingsCryptoKey.value.trim() : '';
    if (newKey && !newKey.startsWith('••')) state.config.apiKey = newKey;
    if (newTav && !newTav.startsWith('••')) state.config.tavilyKey = newTav; else if (!newTav) state.config.tavilyKey = '';
    if (newCryp && !newCryp.startsWith('••')) state.config.cryptoKey = newCryp; else if (!newCryp) state.config.cryptoKey = '';
    state.config.model = settingsModel.value || 'gemini-2.5-flash';
    if (activeModelTag) activeModelTag.textContent = state.config.model;
    state.config.imageModel = settingsImageModel ? settingsImageModel.value || 'imagen-3.0-generate-002' : 'imagen-3.0-generate-002';
    state.config.baseUrl = settingsBaseUrl.value.trim();
    // Switching back to Gemini clears alternative provider
    state.config.provider = 'gemini';
    await chrome.storage.local.set({ pidgeyApiKey: state.config.apiKey, pidgeyModel: state.config.model, pidgeyImageModel: state.config.imageModel, pidgeyBaseUrl: state.config.baseUrl, pidgeyTavilyKey: state.config.tavilyKey, pidgeyCryptoKey: state.config.cryptoKey, pidgeyProvider: 'gemini' });
    settingsSavedMsg.classList.remove('hidden'); setTimeout(() => settingsSavedMsg.classList.add('hidden'), 2000);
    settingsKey.value = '••••••••' + state.config.apiKey.slice(-4);
    settingsTavilyKey.value = state.config.tavilyKey ? '••••••••' + state.config.tavilyKey.slice(-4) : '';
    if (settingsCryptoKey) settingsCryptoKey.value = state.config.cryptoKey ? '••••••••' + state.config.cryptoKey.slice(-4) : '';
    if (activeProviderBadge) { activeProviderBadge.style.display = 'none'; }
});

if (btnSavePreferences) {
    btnSavePreferences.addEventListener('click', async () => {
        state.config.defaultEmail = settingsEmail.value.trim();
        state.config.confirmBeforeAction = settingsConfirmActions.checked;

        const cbVisibleTabs = document.getElementById('settings-visible-tabs');
        if (cbVisibleTabs) state.config.visibleResearchTabs = cbVisibleTabs.checked;
        const cbAutoVision = document.getElementById('settings-auto-vision');
        if (cbAutoVision) state.config.autoVision = cbAutoVision.checked;
        const cbVoiceChat = document.getElementById('settings-voice-chat');
        if (cbVoiceChat) state.config.voiceChat = cbVoiceChat.checked;
        const cbMultiTab = document.getElementById('settings-multi-tab');
        if (cbMultiTab) state.config.multiTab = cbMultiTab.checked;
        const cbShowHints = document.getElementById('settings-show-hints');
        if (cbShowHints) state.config.showHints = cbShowHints.checked;
        const cbVoiceVolume = document.getElementById('settings-voice-volume');
        if (cbVoiceVolume) state.config.voiceVolume = parseFloat(cbVoiceVolume.value);
        const selectVoice = document.getElementById('settings-voice-select');
        if (selectVoice) state.config.voiceURI = selectVoice.value;

        const cbTheme = document.getElementById('settings-theme');
        if (cbTheme) state.config.theme = cbTheme.value;

        if (!state.config.voiceChat && btnMic) btnMic.style.display = 'none';
        else if (btnMic) btnMic.style.display = 'block';

        await chrome.storage.local.set({
            pidgeyEmail: state.config.defaultEmail,
            pidgeyConfirmActions: state.config.confirmBeforeAction,
            pidgeyVisibleTabs: state.config.visibleResearchTabs,
            pidgeyAutoVision: state.config.autoVision,
            pidgeyVoiceChat: state.config.voiceChat,
            pidgeyVoiceVolume: state.config.voiceVolume,
            pidgeyVoiceURI: state.config.voiceURI,
            pidgeyMultiTab: state.config.multiTab,
            pidgeyShowHints: state.config.showHints,
            pidgeyTheme: state.config.theme
        });

        document.body.classList.toggle('dark-mode', state.config.theme === 'dark');

        // Show visual confirmation on the button itself
        if (btnSavePreferences.timeoutId) clearTimeout(btnSavePreferences.timeoutId);
        if (!btnSavePreferences.dataset.origText) {
            btnSavePreferences.dataset.origText = btnSavePreferences.textContent || 'Save Preferences';
            btnSavePreferences.dataset.origBg = btnSavePreferences.style.background || '#475569';
        }

        btnSavePreferences.textContent = '✅ Saved!';
        btnSavePreferences.style.background = '#10b981';

        btnSavePreferences.timeoutId = setTimeout(() => {
            btnSavePreferences.textContent = btnSavePreferences.dataset.origText;
            btnSavePreferences.style.background = btnSavePreferences.dataset.origBg;
            delete btnSavePreferences.dataset.origText;
        }, 2000);
    });

    const prefInputs = [
        'settings-email', 'settings-confirm-actions', 'settings-visible-tabs',
        'settings-auto-vision', 'settings-voice-chat', 'settings-multi-tab',
        'settings-show-hints', 'settings-voice-volume', 'settings-voice-select',
        'settings-theme'
    ];
    prefInputs.forEach(id => {
        const el = document.getElementById(id);
        if (el) {
            el.addEventListener('change', async () => {
                btnSavePreferences.click();
            });
        }
    });
}

// ======== ALTERNATIVE PROVIDER HANDLERS ========
function updateProviderBadge(provider, model) {
    if (!activeProviderBadge) return;
    const labels = { openrouter: 'OpenRouter', openai: 'OpenAI', anthropic: 'Anthropic' };
    const icons = { openrouter: '🔀', openai: '🟢', anthropic: '🟠' };
    activeProviderBadge.innerHTML = `${icons[provider] || '⚡'} Connected to <strong>${labels[provider] || provider}</strong> &mdash; ${model || ''}`;
    activeProviderBadge.style.display = 'block';
    if (activeModelTag && model) activeModelTag.textContent = model;
}

function setProviderStatus(provider, status, text) {
    const el = document.getElementById(`status-${provider}`);
    if (!el) return;
    el.style.display = 'inline-block';
    if (status === 'connected') {
        el.textContent = text || 'Connected';
        el.style.background = '#dcfce7'; el.style.color = '#15803d';
    } else if (status === 'testing') {
        el.textContent = text || 'Testing...';
        el.style.background = '#fef3c7'; el.style.color = '#92400e';
    } else if (status === 'error') {
        el.textContent = text || 'Error';
        el.style.background = '#fee2e2'; el.style.color = '#dc2626';
    } else {
        el.style.display = 'none';
    }
}

function validateKeyFormat(provider, key) {
    if (!key || key.length < 10) return 'API key is too short. Double-check you copied the full key.';
    if (provider === 'openrouter') {
        if (!key.startsWith('sk-or-')) return 'OpenRouter keys start with <strong>sk-or-</strong>. This doesn\'t look like an OpenRouter key. Did you paste a key from a different provider?';
    } else if (provider === 'openai') {
        if (!key.startsWith('sk-')) return 'OpenAI keys start with <strong>sk-</strong>. This doesn\'t look like a valid OpenAI key.';
    } else if (provider === 'anthropic') {
        if (!key.startsWith('sk-ant-')) return 'Anthropic keys start with <strong>sk-ant-</strong>. This doesn\'t look like a valid Anthropic key. Get one from console.anthropic.com';
    }
    return null;
}

async function testProviderConnection(provider, key, model, baseUrl) {
    try {
        let testUrl, testHeaders = { 'Content-Type': 'application/json' }, testBody;
        if (provider === 'anthropic') {
            testUrl = 'https://api.anthropic.com/v1/messages';
            testHeaders['x-api-key'] = key;
            testHeaders['anthropic-version'] = '2023-06-01';
            testBody = JSON.stringify({ model: model || 'claude-sonnet-4-5', max_tokens: 16, messages: [{ role: 'user', content: 'Say "connected" in one word.' }] });
        } else if (provider === 'openai') {
            testUrl = 'https://api.openai.com/v1/chat/completions';
            testHeaders['Authorization'] = `Bearer ${key}`;
            testBody = JSON.stringify({ model: model || 'gpt-4o', max_tokens: 16, messages: [{ role: 'user', content: 'Say "connected" in one word.' }] });
        } else if (provider === 'openrouter') {
            testUrl = 'https://openrouter.ai/api/v1/chat/completions';
            testHeaders['Authorization'] = `Bearer ${key}`;
            testHeaders['HTTP-Referer'] = 'https://pidgeyassist.com';
            testHeaders['X-Title'] = 'Pidgey Assist';
            testBody = JSON.stringify({ model: model || 'google/gemini-2.5-flash', max_tokens: 16, messages: [{ role: 'user', content: 'Say "connected" in one word.' }] });
        } else {
            return { ok: false, error: 'Unknown provider.' };
        }

        const res = await fetch(testUrl, { method: 'POST', headers: testHeaders, body: testBody });

        if (!res.ok) {
            const errData = await res.json().catch(() => ({}));
            const errMsg = errData.error?.message || errData.error?.type || '';
            if (res.status === 401 || res.status === 403) {
                return { ok: false, error: `<strong>Invalid API key.</strong> The provider rejected your key (${res.status}). ${errMsg ? '<br><em>' + errMsg + '</em>' : ''}<br><br>Double-check that you copied the full key and that it hasn\'t been revoked.` };
            }
            if (res.status === 404) {
                return { ok: false, error: `<strong>Model not found:</strong> "${model}".<br>The provider doesn't recognize this model ID. Pick a different model from the dropdown or check the provider's docs.${errMsg ? '<br><em>' + errMsg + '</em>' : ''}` };
            }
            if (res.status === 429) {
                return { ok: false, error: `<strong>Rate limited.</strong> You've hit the API rate limit. This can happen with new/free keys.<br>Wait a minute and try again, or check your plan's usage limits.${errMsg ? '<br><em>' + errMsg + '</em>' : ''}` };
            }
            if (res.status === 402 || res.status === 400) {
                return { ok: false, error: `<strong>Billing/quota issue (${res.status}).</strong> ${errMsg || 'Your account may need credits or a payment method.'}<br>Check your account billing page.` };
            }
            if (res.status >= 500) {
                return { ok: false, error: `<strong>Provider server error (${res.status}).</strong> This is on their end, not yours. Try again in a minute.` };
            }
            return { ok: false, error: `<strong>API Error ${res.status}:</strong> ${errMsg || 'Unknown error. Check your key and model.'}` };
        }
        return { ok: true };
    } catch (err) {
        if (err.message.includes('Failed to fetch') || err.message.includes('NetworkError')) {
            return { ok: false, error: `<strong>Network error.</strong> Couldn't reach the provider's server. Check your internet connection and make sure the URL isn't blocked.` };
        }
        return { ok: false, error: `<strong>Connection failed:</strong> ${err.message}` };
    }
}

async function saveAndTestProvider(provider, key, model) {
    const providerUrls = { openrouter: 'https://openrouter.ai/api/v1', openai: 'https://api.openai.com/v1', anthropic: '__anthropic__' };

    const formatErr = validateKeyFormat(provider, key);
    if (formatErr) {
        showToast(formatErr, 'error', 7000);
        setProviderStatus(provider, 'error', 'Bad key format');
        return false;
    }

    setProviderStatus(provider, 'testing');
    const result = await testProviderConnection(provider, key, model, providerUrls[provider]);

    if (!result.ok) {
        showToast(result.error, 'error', 10000);
        setProviderStatus(provider, 'error', 'Failed');
        return false;
    }

    state.config.apiKey = key;
    state.config.model = model;
    state.config.baseUrl = providerUrls[provider];
    state.config.provider = provider;
    await chrome.storage.local.set({ pidgeyProvider: provider, pidgeyAltKey: key, pidgeyAltModel: model });
    updateProviderBadge(provider, model);
    setProviderStatus(provider, 'connected');
    const labels = { openrouter: 'OpenRouter', openai: 'OpenAI', anthropic: 'Anthropic' };
    showToast(`<strong>${labels[provider]} connected!</strong><br>Model: ${model}<br>Pidgey is now using your key.`, 'success', 4000);
    return true;
}

if (btnSaveOpenrouter) {
    btnSaveOpenrouter.addEventListener('click', async () => {
        const key = settingsOpenrouterKey?.value.trim();
        const model = settingsOpenrouterModel?.value.trim() || 'google/gemini-2.5-flash';
        if (!key) { showToast('<strong>Paste your OpenRouter API key first.</strong><br>Get a free one at openrouter.ai/keys', 'warning'); return; }
        btnSaveOpenrouter.disabled = true; btnSaveOpenrouter.textContent = 'Testing...';
        await saveAndTestProvider('openrouter', key, model);
        btnSaveOpenrouter.disabled = false; btnSaveOpenrouter.textContent = 'Connect & Test';
    });
}

if (btnSaveOpenai) {
    btnSaveOpenai.addEventListener('click', async () => {
        const key = settingsOpenaiKey?.value.trim();
        const model = settingsOpenaiModel?.value.trim() || 'gpt-4o';
        if (!key) { showToast('<strong>Paste your OpenAI API key first.</strong><br>Get one at platform.openai.com/api-keys', 'warning'); return; }
        btnSaveOpenai.disabled = true; btnSaveOpenai.textContent = 'Testing...';
        await saveAndTestProvider('openai', key, model);
        btnSaveOpenai.disabled = false; btnSaveOpenai.textContent = 'Connect & Test';
    });
}

if (btnSaveAnthropic) {
    btnSaveAnthropic.addEventListener('click', async () => {
        const key = settingsAnthropicKey?.value.trim();
        const model = settingsAnthropicModel?.value.trim() || 'claude-sonnet-4-5';
        if (!key) { showToast('<strong>Paste your Anthropic API key first.</strong><br>Get one at console.anthropic.com/settings/keys', 'warning'); return; }
        btnSaveAnthropic.disabled = true; btnSaveAnthropic.textContent = 'Testing...';
        await saveAndTestProvider('anthropic', key, model);
        btnSaveAnthropic.disabled = false; btnSaveAnthropic.textContent = 'Connect & Test';
    });
}

const btnResetProvider = document.getElementById('btn-reset-provider');
if (btnResetProvider) {
    btnResetProvider.addEventListener('click', async () => {
        const sync = await chrome.storage.local.get(['pidgeyApiKey', 'pidgeyModel']);
        state.config.apiKey = sync.pidgeyApiKey || '';
        state.config.model = sync.pidgeyModel || 'gemini-2.0-flash';
        state.config.baseUrl = '';
        state.config.provider = 'gemini';
        await chrome.storage.local.set({ pidgeyProvider: 'gemini', pidgeyAltKey: '', pidgeyAltModel: '' });
        if (activeProviderBadge) activeProviderBadge.style.display = 'none';
        if (activeModelTag) activeModelTag.textContent = state.config.model;
        setProviderStatus('openrouter', 'hide');
        setProviderStatus('openai', 'hide');
        setProviderStatus('anthropic', 'hide');
        if (settingsOpenrouterKey) settingsOpenrouterKey.value = '';
        if (settingsOpenrouterModel) settingsOpenrouterModel.value = '';
        if (settingsOpenaiKey) settingsOpenaiKey.value = '';
        if (settingsOpenaiModel) settingsOpenaiModel.value = '';
        if (settingsAnthropicKey) settingsAnthropicKey.value = '';
        if (settingsAnthropicModel) settingsAnthropicModel.value = '';
        showToast('Switched back to <strong>default Gemini</strong> provider.', 'info', 3000);
    });
}

document.querySelectorAll('.btn-reveal-key').forEach(btn => {
    btn.addEventListener('click', () => {
        const target = document.getElementById(btn.dataset.target);
        if (!target) return;
        if (target.type === 'password') {
            target.type = 'text';
            btn.textContent = '🙈';
        } else {
            target.type = 'password';
            btn.textContent = '👁';
        }
    });
});

btnClear.addEventListener('click', async () => {
    state.chatHistory.length = 0;
    messagesEl.innerHTML = '';
    await chrome.storage.local.remove('pidgeyChatHistory');
    const p = PERSONAS[state.activePersona] || PERSONAS.assist;
    addBotMessage(`Chirp! Fresh start as ${p.name}! ${p.icon} What can I help you with?`);
});

const updateSidebarActive = (activeBtn) => {
    document.querySelectorAll('.sidebar-btn').forEach(btn => btn.classList.remove('active'));
    if (activeBtn) activeBtn.classList.add('active');
};

if (btnSidebarChat) {
    btnSidebarChat.addEventListener('click', () => {
        if (settingsPanel) settingsPanel.classList.add('hidden');
        if (backpackPanel) backpackPanel.classList.add('hidden');
        if (agentPanel) agentPanel.classList.add('hidden');
        if (providersPanel) providersPanel.classList.add('hidden');
        if (personasPanel) personasPanel.classList.add('hidden');
        updateSidebarActive(btnSidebarChat);
    });
}

const togglePersonasPanel = () => {
    if (settingsPanel) settingsPanel.classList.add('hidden');
    if (backpackPanel) backpackPanel.classList.add('hidden');
    if (agentPanel) agentPanel.classList.add('hidden');
    if (providersPanel) providersPanel.classList.add('hidden');
    const isHidden = personasPanel.classList.toggle('hidden');
    updateSidebarActive(isHidden ? btnSidebarChat : btnPersonas);
};

btnPersonas.addEventListener('click', togglePersonasPanel);
if (btnProviders) {
    btnProviders.addEventListener('click', () => {
        if (settingsPanel) settingsPanel.classList.add('hidden');
        if (backpackPanel) backpackPanel.classList.add('hidden');
        if (agentPanel) agentPanel.classList.add('hidden');
        if (personasPanel) personasPanel.classList.add('hidden');
        const isHidden = providersPanel.classList.toggle('hidden');
        updateSidebarActive(isHidden ? btnSidebarChat : btnProviders);
    });
}

personaDisplay.addEventListener('click', togglePersonasPanel);

document.querySelectorAll('.persona-option-btn').forEach(btn => {
    btn.addEventListener('click', async () => {
        const newPersona = btn.getAttribute('data-val');
        if (newPersona === state.activePersona) {
            personasPanel.classList.add('hidden');
            return;
        }

        const pInfo = PERSONAS[newPersona];

        if (state.chatHistory.length > 2) {
            const confirmSwitch = confirm(`Switching to ${pInfo.name} requires clearing the current chat so Pidgey can focus. Is this okay?`);
            if (!confirmSwitch) return;
        }

        state.activePersona = newPersona;
        personaDisplay.textContent = `${pInfo.icon} ${pInfo.name}`;
        await chrome.storage.local.set({ pidgeyPersona: newPersona });

        state.chatHistory.length = 0;
        messagesEl.innerHTML = '';
        await chrome.storage.local.remove('pidgeyChatHistory');

        personasPanel.classList.add('hidden');
        addBotMessage(`Chirp! Switched to **${pInfo.name}**! ${pInfo.icon}\n\nMy brain has rewired. What's the mission?`);

        if (typeof window.updatePersonaUI === 'function') window.updatePersonaUI();
    });
});

btnSend.addEventListener('click', () => sendMessage());
chatInput.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } });

document.querySelectorAll('.preset-btn, .btn-prompt-launch').forEach(btn => { btn.addEventListener('click', () => { const p = btn.getAttribute('data-prompt'); if (p) { chatInput.value = p; sendMessage(); } }); });

const PHOENIX_MSG = `🔥 **Phoenix Upgrade Required**\n\nChirp! I'd love to help out, but you need the Phoenix upgrade to unlock this capability!\n\n**Free Tier Features:**\n- 💬 AI Web Copilot & Chat\n- 📝 Instant Page Summaries\n\n**Phoenix Tier Features:**\n- 🎒 Pidgey Backpack Storage\n- 📊 Advanced Chart Analysis\n- 🎨 Custom Image Gen\n- 🔬 Deep Research Mode\n- 🧮 Complex Data Analysis\n- 🥚 Long-term Memory\n- ✏️ Autofill Automations\n- 🎤 Voice Interactions\n\n*Would you like to upgrade? Just click the **⬆️ Upgrade** button in the menu above to see the offer!*`;

// ======== QUICK MENU ========
const btnQuickMenu = $('btn-quick-menu');
const btnSidebarQuickMenu = $('btn-sidebar-quick-menu');
const quickMenu = $('quick-menu');
if (btnQuickMenu && quickMenu) {
    btnQuickMenu.addEventListener('click', (e) => {
        e.stopPropagation();
        quickMenu.classList.toggle('hidden');
    });

    if (btnSidebarQuickMenu) {
        btnSidebarQuickMenu.addEventListener('click', (e) => {
            e.stopPropagation();
            quickMenu.classList.toggle('hidden');
        });
    }

    document.addEventListener('click', (e) => {
        if (!quickMenu.classList.contains('hidden') && !quickMenu.contains(e.target) && e.target !== btnQuickMenu && e.target !== btnSidebarQuickMenu) {
            quickMenu.classList.add('hidden');
        }
    });

    document.querySelectorAll('.quick-menu-item').forEach(btn => {
        btn.addEventListener('click', () => {
            if (btn.classList.contains('phoenix-locked') && !document.body.classList.contains('phoenix-mode')) {
                addBotMessage(PHOENIX_MSG);
                quickMenu.classList.add('hidden');
                return;
            }
            const p = btn.getAttribute('data-prompt');
            if (p) {
                chatInput.value = p;
                quickMenu.classList.add('hidden');
                sendMessage();
            }
        });
    });
}


// ======== UI EXTRAS ========

if (btnVision) {
    // Restore state if we want, but default memory is fine
    btnVision.addEventListener('click', () => {
        state.autoVision = !state.autoVision;
        btnVision.classList.toggle('active', state.autoVision);
        btnVision.title = state.autoVision ? "Auto-Vision (ON)" : "Auto-Vision (OFF)";
        chatInput.placeholder = state.autoVision ? "Ask Pidgey (Vision ON)..." : "Ask Pidgey anything...";
    });
}

// ======== VOICE ========
let recognition = null, isRecording = false;
window.isPidgeyVoiceMode = false;
const SpeechRec = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SpeechRec) {
    recognition = new SpeechRec();
    recognition.continuous = false; recognition.interimResults = true; recognition.lang = 'en-US';
    recognition.onstart = () => { isRecording = true; btnMic.classList.add('recording'); chatInput.placeholder = 'Listening...'; };
    recognition.onresult = e => { let f = '', i = ''; for (let x = e.resultIndex; x < e.results.length; x++) { if (e.results[x].isFinal) f += e.results[x][0].transcript; else i += e.results[x][0].transcript; } chatInput.value = f || i; };
    recognition.onerror = e => { 
        if (e.error === 'not-allowed') {
            chrome.tabs.create({ url: chrome.runtime.getURL('mic_permission.html') }); 
        } else if (e.error !== 'no-speech') {
            addBotMessage(`🎤 **Voice Mode Error:** \`${e.error}\`\n\nPidgey had trouble listening. Please check your microphone connection.`);
        }
        stopRec(); 
    };
    recognition.onend = () => {
        isRecording = false;
        if (!window.isPidgeyVoiceMode) btnMic.classList.remove('recording');
        chatInput.placeholder = 'Ask Pidgey anything...';
        if (chatInput.value.trim()) sendMessage();
        else if (window.isPidgeyVoiceMode) { try { recognition.start(); } catch { } }
    };
}
function stopRec() {
    isRecording = false;
    window.isPidgeyVoiceMode = false;
    btnMic.classList.remove('recording');
    chatInput.placeholder = 'Ask Pidgey anything...';
}
btnMic.addEventListener('click', () => {
    if (!document.body.classList.contains('phoenix-mode')) {
        addBotMessage(PHOENIX_MSG);
        return;
    }
    if (!recognition) { addBotMessage("Chirp! 😢 Your browser doesn't support voice."); return; }
    if (isRecording || window.isPidgeyVoiceMode) {
        window.isPidgeyVoiceMode = false;
        recognition.stop();
        window.speechSynthesis.cancel();
        btnMic.classList.remove('recording');
    } else {
        window.speechSynthesis.cancel();
        window.isPidgeyVoiceMode = true;
        chatInput.value = '';
        recognition.start();
    }
});

document.addEventListener('pidgey_mic_stop', () => {
    if (recognition && isRecording) {
        try { recognition.abort(); } catch { }
        isRecording = false;
        btnMic.classList.remove('recording');
    }
});

document.addEventListener('pidgey_mic_restart', () => {
    if (window.isPidgeyVoiceMode && !isRecording) {
        chatInput.value = '';
        try { recognition.start(); } catch { }
    }
});

// ======== DRAG AND DROP ========
const dropOverlay = $('drop-overlay');
let dragCounter = 0;
window.addEventListener('dragenter', e => { e.preventDefault(); dragCounter++; if (dropOverlay) dropOverlay.classList.remove('hidden'); });
window.addEventListener('dragleave', e => { e.preventDefault(); dragCounter--; if (dragCounter === 0 && dropOverlay) dropOverlay.classList.add('hidden'); });
window.addEventListener('dragover', e => e.preventDefault());
window.addEventListener('drop', e => {
    e.preventDefault(); dragCounter = 0; if (dropOverlay) dropOverlay.classList.add('hidden');
    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
        const file = e.dataTransfer.files[0];
        if (file.size > 2 * 1024 * 1024) { addBotMessage("Chirp! 😱 That file is over 2MB. I can only digest smaller texts and docs right now!"); return; }

        const isDoc = file.name.match(/\.(docx|doc|odt|rtf|pdf)$/i);

        if (isDoc) {
            addBotMessage(`Chirp! Reading ${file.name} using LibreOffice integration...`);
            const reader = new FileReader();
            reader.onload = async (event) => {
                const base64Data = event.target.result.split(',')[1];
                try {
                    const res = await fetch("http://localhost:3000/api/libreoffice/read", {
                        method: "POST",
                        headers: { 
                            "Content-Type": "application/json",
                            "Authorization": "Bearer pidgey_local_dev_token"
                        },
                        body: JSON.stringify({ base64Data, filename: file.name })
                    });
                    const data = await res.json();
                    if (data.success) {
                        ingestFileToBackpack(file.name, data.content);
                    } else {
                        addBotMessage(`Failed to read document natively: ${data.error}`);
                    }
                } catch (err) {
                    addBotMessage("Chirp! The local Pidgey server isn't running to process LibreOffice documents.");
                }
            };
            reader.readAsDataURL(file);
        } else {
            const reader = new FileReader();
            reader.onload = async (event) => {
                const textContent = event.target.result;
                ingestFileToBackpack(file.name, textContent);
            };
            reader.onerror = () => addBotMessage("Chirp! 😢 I couldn't read that file.");
            reader.readAsText(file);
        }
    }
});

async function ingestFileToBackpack(fileName, fullText) {
    if (!state.config.apiKey) {
        await chrome.storage.local.set({ [`_file_${fileName}`]: fullText });
        addBotMessage(`🎒 **Ingested (Basic):** ${fileName} was added to your Backpack! (API Key needed for Smart Ingestion)`);
        if (!backpackPanel.classList.contains('hidden')) loadBackpackFiles();
        return;
    }

    addBotMessage(`🧠 **Librarian Pidgey:** Reading and summarizing [${fileName}]...`);

    try {
        const summaryRes = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${DEFAULT_MODEL}:generateContent`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'x-goog-api-key': state.config.apiKey },
            body: JSON.stringify({
                system_instruction: { parts: [{ text: "You are The Librarian. Output a precise 3-sentence summary covering what the document is, key entities, and main facts." }] },
                contents: [{ role: 'user', parts: [{ text: `Summarize this natively:\n\n${fullText.substring(0, 15000)}` }] }]
            })
        });
        const sumData = await summaryRes.json();
        const summaryText = sumData?.candidates?.[0]?.content?.parts?.[0]?.text || 'No summary generated.';
        await chrome.storage.local.set({ [`_meta_${fileName}`]: summaryText });

        addBotMessage(`🧠 **Librarian Summary for ${fileName}:**\n\n> ${summaryText}\n\n*Now vectorizing sentences for Deep Vector Search...*`);

        let chunks = fullText.split(/\n\s*\n/);
        if (chunks.length <= 1) chunks = fullText.match(/[^.!?]+[.!?]+/g) || [fullText];

        let mergedChunks = [];
        let curr = "";
        for (let c of chunks) {
            curr += c + "\\n";
            if (curr.length > 500) { mergedChunks.push(curr.trim()); curr = ""; }
        }
        if (curr.trim()) mergedChunks.push(curr.trim());
        mergedChunks = mergedChunks.slice(0, 80);

        const embedReqs = mergedChunks.map(str => ({ model: `models/${EMBEDDING_MODEL}`, content: { parts: [{ text: str }] } }));
        const embUrl = `https://generativelanguage.googleapis.com/v1beta/models/${EMBEDDING_MODEL}:batchEmbedContents`;
        const embRes = await fetch(embUrl, { method: "POST", headers: { "Content-Type": "application/json", "x-goog-api-key": state.config.apiKey }, body: JSON.stringify({ requests: embedReqs }) });
        const embData = await embRes.json();

        const vectors = [];
        if (embData.embeddings) {
            embData.embeddings.forEach((emb, i) => { vectors.push({ text: mergedChunks[i], values: emb.values }); });
        }

        await chrome.storage.local.set({
            [`_file_${fileName}`]: fullText,
            [`_rag_${fileName}`]: JSON.stringify(vectors)
        });

        addBotMessage(`🎒 **Fully Ingested & Vectorized:** [${fileName}] is deeply mapped into your Backpack Memory! You can ask me to search its contents.`);
        if (!backpackPanel.classList.contains('hidden')) loadBackpackFiles();
    } catch (err) {
        console.error("Ingest error", err);
        await chrome.storage.local.set({ [`_file_${fileName}`]: fullText });
        addBotMessage(`🎒 **Ingested (Basic):** ${fileName} was saved, but Smart Vectorization failed.`);
        if (!backpackPanel.classList.contains('hidden')) loadBackpackFiles();
    }
}


// ======== START ========
try {
    init();
} catch (e) {
    console.error("Initialization failed", e);
    // If we crash at the very start, at least try to show something
    document.body.innerHTML += `<div style="position:fixed;inset:0;background:rgba(0,0,0,0.8);color:white;display:flex;align-items:center;justify-content:center;padding:20px;text-align:center;z-index:9999;">🚨 Pidgey Initialization Error: ${e.message}<br><br>Please try reloading the extension.</div>`;
}

function populateVoiceList() {
    const selectVoice = document.getElementById('settings-voice-select');
    if (!selectVoice) return;
    const voices = window.speechSynthesis.getVoices();
    if (!voices.length) return;

    selectVoice.innerHTML = '<option value="">Default Voice</option>';

    voices.forEach(voice => {
        const option = document.createElement('option');
        option.textContent = `${voice.name} (${voice.lang})`;

        if (voice.default) {
            option.textContent += ' -- DEFAULT';
        }

        option.setAttribute('data-lang', voice.lang);
        option.setAttribute('data-name', voice.name);
        option.value = voice.voiceURI;
        selectVoice.appendChild(option);
    });

    if (state.config.voiceURI) {
        selectVoice.value = state.config.voiceURI;
    }
}

// ======== DESIGNER PIDGEY: GLOBAL CHAT DROP HANDLERS ========
window.handleChatDrop = function (e) {
    e.preventDefault();
    e.stopPropagation();

    // Reset hover styles
    const inputWrap = document.getElementById('chat-input-wrap');
    if (inputWrap) {
        inputWrap.style.borderColor = 'transparent';
        inputWrap.style.background = 'white';
    }

    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
        const file = e.dataTransfer.files[0];
        if (file.type.startsWith('image/')) {
            window.currentChatAttachment = file;
            const previewWrap = document.getElementById('chat-attachment-preview');
            const previewImg = document.getElementById('chat-attachment-img');
            const previewName = document.getElementById('chat-attachment-name');

            if (previewWrap && previewImg && previewName) {
                previewName.textContent = file.name;
                const reader = new FileReader();
                reader.onload = (e) => {
                    previewImg.src = e.target.result;
                    previewWrap.style.display = 'flex';
                };
                reader.readAsDataURL(file);
            }
        }
    }
};

window.removeChatAttachment = function () {
    window.currentChatAttachment = null;
    const previewWrap = document.getElementById('chat-attachment-preview');
    if (previewWrap) {
        previewWrap.style.display = 'none';
    }
};

document.addEventListener("DOMContentLoaded", () => {
    const inputWrap = document.getElementById("chat-input-wrap");
    if (inputWrap) {
        inputWrap.addEventListener("dragover", (e) => {
            e.preventDefault();
            inputWrap.style.borderColor = "#3b82f6";
            inputWrap.style.background = "rgba(59,130,246,0.1)";
        });
        inputWrap.addEventListener("dragleave", (e) => {
            inputWrap.style.borderColor = "transparent";
            inputWrap.style.background = "white";
        });
        inputWrap.addEventListener("drop", window.handleChatDrop);
    }
    const btnRemove = document.getElementById("btn-remove-attachment");
    if (btnRemove) {
        btnRemove.addEventListener("click", window.removeChatAttachment);
    }
});

// Ensure visual badge clears if user violently closes Side Panel during operations
window.addEventListener('unload', () => {
    try {
        if (state.agentRunning || state.isGenerating) {
            chrome.action.setBadgeText({ text: '' });
        }
    } catch { }
});
