// Popup script – manages extension settings and browsing history
// API key is encrypted via AES-GCM before storing in chrome.storage.local.
// Uses safe DOM methods (createElement / textContent) throughout.

const DEFAULT_MODELS = {
  openai: 'gpt-4o-mini',
  claude: 'claude-sonnet-4-20250514',
  kimi: 'moonshot-v1-8k',
  zhipu: 'glm-4-flash',
};

// Theme cycle order: auto → light → dark → auto
const THEME_CYCLE = ['auto', 'light', 'dark'];

// ── Global keyboard shortcuts ──────────────────────────────────────────────
document.addEventListener('keydown', (e) => {
  const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
  const modKey = isMac ? e.metaKey : e.ctrlKey;

  // Cmd/Ctrl + K: Focus search
  if (modKey && e.key === 'k') {
    e.preventDefault();
    const searchInput = document.getElementById('historySearch');
    if (searchInput) {
      searchInput.focus();
    }
    return;
  }

  // Cmd/Ctrl + S: Save settings
  if (modKey && e.key === 's') {
    e.preventDefault();
    const saveBtn = document.getElementById('saveSettingsBtn');
    if (saveBtn && !saveBtn.disabled) {
      saveBtn.click();
    }
    return;
  }

  // ?: Show shortcuts help
  if (e.key === '?' && !e.ctrlKey && !e.metaKey && !e.altKey) {
    e.preventDefault();
    openShortcutsModal();
    return;
  }

  // Escape: Clear search or close modals
  if (e.key === 'Escape') {
    const modal = document.getElementById('shortcutsModal');
    if (modal && !modal.classList.contains('hidden')) {
      closeShortcutsModal();
      return;
    }

    const searchInput = document.getElementById('historySearch');
    if (searchInput && searchInput.value) {
      searchInput.value = '';
      searchInput.dispatchEvent(new Event('input'));
    }
  }
});

// Shortcuts Modal Functions
function openShortcutsModal() {
  const modal = document.getElementById('shortcutsModal');
  if (modal) {
    modal.classList.remove('hidden');
  }
}

function closeShortcutsModal() {
  const modal = document.getElementById('shortcutsModal');
  if (modal) {
    modal.classList.add('hidden');
  }
}

// Modal close button and overlay click
document.addEventListener('DOMContentLoaded', () => {
  const modalClose = document.querySelector('.modal-close');
  if (modalClose) {
    modalClose.addEventListener('click', closeShortcutsModal);
  }

  const modalOverlay = document.querySelector('.modal-overlay');
  if (modalOverlay) {
    modalOverlay.addEventListener('click', closeShortcutsModal);
  }
});

// ── Init ──────────────────────────────────────────────────────────────────────

document.addEventListener('DOMContentLoaded', () => {
  initTheme();
  migrateAndLoadSettings();
  setupTabs();
  initDashboard(); // Load stats and recent
  loadHistory();   // Preload history list
  initDashboard(); // Load stats and recent
  loadHistory();   // Preload history list
  const providerEl = document.getElementById('provider');
  if (providerEl) {
    providerEl.addEventListener('change', (e) => {
      updateModelHint(e.target.value);
      saveSettings();
    });
  }

  const toggleKeyBtn = document.getElementById('toggleKey');
  if (toggleKeyBtn) {
    toggleKeyBtn.addEventListener('click', toggleKeyVisibility);
  }

  // Auto-save API Key on blur
  const apiKeyInput = document.getElementById('apiKey');
  if (apiKeyInput) {
    console.log('[popup] API Key input found, attaching auto-save listeners');
    apiKeyInput.addEventListener('blur', () => {
      console.log('[popup] API Key blur event triggered, calling saveSettings');
      saveSettings();
    });
    // Also save on Enter key
    apiKeyInput.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        console.log('[popup] Enter key pressed in API Key input');
        apiKeyInput.blur(); // Trigger blur to save
      }
    });
  } else {
    console.error('[popup] API Key input NOT FOUND');
  }

  const clearHistoryBtn = document.getElementById('clearHistoryBtn');
  if (clearHistoryBtn) {
    clearHistoryBtn.addEventListener('click', clearHistory);
  }

  const themeToggle = document.getElementById('themeToggle');
  if (themeToggle) {
    themeToggle.addEventListener('click', cycleTheme);
  }

  // Auto-save switches
  const autoDownloadEl = document.getElementById('autoDownloadMd');
  if (autoDownloadEl) {
    autoDownloadEl.addEventListener('change', (e) => {
      toggleSavePathVisibility();
      saveSettings();
    });
  }

  const aiEnabledEl = document.getElementById('aiEnabled');
  if (aiEnabledEl) {
    aiEnabledEl.addEventListener('change', (e) => {
      toggleAiFields();
      saveSettings();
    });
  }

  const pickFolderBtn = document.getElementById('pickFolderBtn');
  if (pickFolderBtn) {
    pickFolderBtn.addEventListener('click', pickFolder);
  }

  const clearFolderBtn = document.getElementById('clearFolderBtn');
  if (clearFolderBtn) {
    clearFolderBtn.addEventListener('click', clearFolder);
  }

  const nativeSetupBtn = document.getElementById('nativeSetupBtn');
  if (nativeSetupBtn) {
    nativeSetupBtn.addEventListener('click', downloadInstallScript);
  }

  const copyBtn = document.getElementById('copyDebugBtn');
  if (copyBtn) copyBtn.addEventListener('click', copyDebugInfo);

  // Export/Import buttons
  const exportBtn = document.getElementById('exportHistoryBtn');
  const importBtn = document.getElementById('importHistoryBtn');
  if (exportBtn) exportBtn.addEventListener('click', showExportDialog);
  if (importBtn) importBtn.addEventListener('click', importHistory);

  initFooter();

  // Listen for storage changes so the UI updates when background saves
  // the folder path (after the native picker dialog completes).
  chrome.storage.onChanged.addListener(function (changes, area) {
    if (area === 'sync' && changes.mdFolderPath) {
      var newPath = changes.mdFolderPath.newValue || '';
      var newName = (changes.mdFolderName && changes.mdFolderName.newValue) || '';
      if (newPath) {
        displaySelectedFolder(newName || newPath.split('/').pop(), newPath);
        showStatus('文件夹已选择', 'success');
      }
    }
  });

  // Language Switcher
  const langSelect = document.getElementById('appLanguage');
  if (langSelect) {
    console.log('Language selector found');
    langSelect.addEventListener('change', (e) => {
      const newLang = e.target.value;
      console.log('Language changed to:', newLang);
      chrome.storage.sync.set({ language: newLang });
      updateLanguage(newLang);
    });
  } else {
    console.error('Language selector NOT found');
  }

  // Load debug info when the debug section is opened
  document.getElementById('debugSection').addEventListener('toggle', function () {
    if (this.open) loadDebugInfo();
  });
});

// ── Theme management ────────────────────────────────────────────────────────

function initTheme() {
  chrome.storage.sync.get({ theme: 'auto' }, function (data) {
    applyTheme(data.theme);
  });
}

function applyTheme(theme) {
  document.documentElement.setAttribute('data-theme', theme);
  document.body.setAttribute('data-theme', theme);
}

function cycleTheme() {
  var currentTheme = document.documentElement.getAttribute('data-theme') || 'auto';
  var idx = THEME_CYCLE.indexOf(currentTheme);
  var nextTheme = THEME_CYCLE[(idx + 1) % THEME_CYCLE.length];
  applyTheme(nextTheme);
  chrome.storage.sync.set({ theme: nextTheme });
}

// ── Language Management ─────────────────────────────────────────────────────

function updateLanguage(lang) {
  console.log('updateLanguage called with:', lang);
  // Update html lang attribute
  document.documentElement.lang = lang;

  // Update all elements with data-i18n
  const elements = document.querySelectorAll('[data-i18n]');
  console.log('Found i18n elements:', elements.length);

  elements.forEach(el => {
    const key = el.getAttribute('data-i18n');
    // Ensure t is available
    if (typeof t !== 'function') {
      console.error('Translation function t() not found!');
      return;
    }
    const val = t(key, lang);
    console.log(`Translating ${key} -> ${val}`);
    el.textContent = val;
  });

  // Update placeholders
  const searchInput = document.getElementById('historySearch');
  if (searchInput) searchInput.placeholder = t('history.search', lang);

  // Re-render dynamic content
  initDashboard();
  loadHistory();
}

// ── API Key encryption (AES-GCM via Web Crypto API) ─────────────────────────

async function getOrCreateEncryptionKey() {
  var stored = await chrome.storage.local.get('encKey');
  if (stored.encKey) {
    try {
      return await crypto.subtle.importKey(
        'raw', new Uint8Array(stored.encKey), 'AES-GCM', false, ['encrypt', 'decrypt']
      );
    } catch (e) {
      console.warn('Corrupted encryption key detected, resetting...', e);
      await chrome.storage.local.remove(['encKey', 'encryptedApiKey']);
    }
  }
  // Generate new key if missing or corrupted
  var key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
  var exported = await crypto.subtle.exportKey('raw', key);
  await chrome.storage.local.set({ encKey: Array.from(new Uint8Array(exported)) });
  return key;
}

async function encryptApiKey(plaintext) {
  var key = await getOrCreateEncryptionKey();
  var iv = crypto.getRandomValues(new Uint8Array(12));
  var encoded = new TextEncoder().encode(plaintext);
  var ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv: iv }, key, encoded);
  return { iv: Array.from(iv), data: Array.from(new Uint8Array(ciphertext)) };
}

async function decryptApiKey(encrypted) {
  try {
    var key = await getOrCreateEncryptionKey();
    var decrypted = await crypto.subtle.decrypt(
      { name: 'AES-GCM', iv: new Uint8Array(encrypted.iv) },
      key,
      new Uint8Array(encrypted.data)
    );
    return new TextDecoder().decode(decrypted);
  } catch (e) {
    console.error('Decryption failed:', e);
    throw e;
  }
}

// ── Migration from plaintext sync storage ────────────────────────────────────

async function migrateAndLoadSettings() {
  var syncData = await chrome.storage.sync.get({
    provider: 'openai',
    apiKey: '',
    language: 'zh-CN',
    mdMode: 'tldr',
    model: '',
    baseUrl: '',
    autoDownloadMd: true,
    mdFolderPath: '',  // folder path saved by background.js via native picker
    theme: 'auto',
    aiEnabled: true,
  });

  // If a plaintext key exists in sync, migrate it
  if (syncData.apiKey) {
    var encrypted = await encryptApiKey(syncData.apiKey);
    await chrome.storage.local.set({ encryptedApiKey: encrypted });
    await chrome.storage.sync.remove('apiKey');
  }

  // Load the encrypted key for display
  var apiKeyPlain = '';
  var localData = await chrome.storage.local.get('encryptedApiKey');
  if (localData.encryptedApiKey) {
    try {
      apiKeyPlain = await decryptApiKey(localData.encryptedApiKey);
    } catch (e) {
      console.error('API Key restore failed:', e);
      showStatus('API Key 解密失败，请重新输入', 'error');
    }
  }

  document.getElementById('provider').value = syncData.provider;
  document.getElementById('apiKey').value = apiKeyPlain;

  // Fix: ID is appLanguage, not language
  const langSelect = document.getElementById('appLanguage');
  if (langSelect) langSelect.value = syncData.language;

  updateLanguage(syncData.language); // Apply language

  const mdModeEl = document.getElementById('mdMode');
  if (mdModeEl) mdModeEl.value = syncData.mdMode || 'tldr';

  const modelEl = document.getElementById('model');
  if (modelEl) modelEl.value = syncData.model;

  const baseUrlEl = document.getElementById('baseUrl');
  if (baseUrlEl) baseUrlEl.value = syncData.baseUrl || '';

  document.getElementById('autoDownloadMd').checked = syncData.autoDownloadMd;
  document.getElementById('aiEnabled').checked = syncData.aiEnabled !== false;
  updateModelHint(syncData.provider);
  toggleSavePathVisibility();
  toggleAiFields();

  // Load folder display from stored path
  if (syncData.mdFolderPath) {
    var name = syncData.mdFolderPath.split('/').pop();
    displaySelectedFolder(name, syncData.mdFolderPath);
  }



  // Check native host status and update UI accordingly
  checkNativeHost().then(function (available) {
    nativeHostAvailable = available;
    var textEl = document.getElementById('nativeSetupText');
    var btn = document.getElementById('nativeSetupBtn');

    if (textEl && btn) {
      if (available) {
        textEl.textContent = 'Native Helper 已安装。如需重装或更新，可重新下载脚本运行。';
        btn.textContent = '重新下载安装脚本';
        updateSavePathHint(true);
      } else {
        textEl.textContent = '浏览器扩展受沙盒限制，无法直接写入自定义文件夹。安装 Native Helper 后即可选择任意保存路径。';
        btn.textContent = '一键下载安装脚本';
        var pickBtn = document.getElementById('pickFolderBtn');
        if (pickBtn) pickBtn.disabled = true;
        updateSavePathHint(false);
      }
    } else {
      // Just update the hint if the full setup UI is missing
      updateSavePathHint(available);
    }
  });
}

// ── Native host detection ─────────────────────────────────────────────────────

async function checkNativeHost() {
  try {
    var result = await chrome.runtime.sendMessage({ type: 'PING_NATIVE_HOST' });
    return !!(result && result.success);
  } catch (_) {
    return false;
  }
}

// ── Folder picker (native messaging host) ────────────────────────────────────

// Track whether native host is available (checked once on popup open)
var nativeHostAvailable = false;

// Show or hide save path section based on auto-download checkbox
function toggleSavePathVisibility() {
  var checked = document.getElementById('autoDownloadMd').checked;
  var group = document.getElementById('savePathGroup');
  if (group) {
    group.style.display = checked ? 'block' : 'none';
  }
}

// Toggle AI config fields and save mode visibility based on AI toggle state.
// Persists immediately so the setting takes effect without clicking "保存设置".
function toggleAiFields() {
  var enabledEl = document.getElementById('aiEnabled');
  if (!enabledEl) return;

  var enabled = enabledEl.checked;
  var card = document.getElementById('aiConfigCard');
  var mdModeGroup = document.getElementById('mdModeGroup');

  if (card) {
    if (enabled) {
      card.classList.remove('ai-disabled');
    } else {
      card.classList.add('ai-disabled');
    }
  }

  if (mdModeGroup) {
    mdModeGroup.style.display = enabled ? 'block' : 'none';
  }

  chrome.storage.sync.set({ aiEnabled: enabled });
}

// Update the hint text below the folder picker based on current state
function updateSavePathHint(available) {
  var hintEl = document.getElementById('savePathHint');
  if (!hintEl) return;

  var folderPathEl = document.getElementById('folderPath');
  var hasFolder = folderPathEl && folderPathEl.classList.contains('active');
  if (hasFolder) {
    return; // hint is set by displaySelectedFolder
  }
  if (available) {
    hintEl.textContent = '未选择文件夹，保存到下载目录 antimark 子文件夹';
  } else {
    hintEl.textContent = '安装 Native Helper 后可选择任意文件夹保存';
  }
}

// Fire-and-forget: send pick request to background, don't block the popup.
// Background opens the native macOS folder picker (osascript), saves the
// result to sync storage. The popup's onChanged listener updates the UI.
function pickFolder() {
  if (!nativeHostAvailable) {
    showStatus('请先安装 Native Helper', 'error');
    return;
  }
  // Fire and forget — do NOT await this
  chrome.runtime.sendMessage({ type: 'PICK_NATIVE_FOLDER' });
  showStatus('文件夹选择对话框已打开...', 'success');
}

function clearFolder() {
  chrome.storage.sync.remove(['mdFolderPath', 'mdFolderName']);
  displayNoFolder();
  updateSavePathHint(nativeHostAvailable);
  showStatus('已清除，将保存到下载目录', 'success');
}

function displaySelectedFolder(name, path) {
  var pathEl = document.getElementById('folderPath');
  if (path) {
    // Show shortened path: replace /Users/xxx with ~
    var displayPath = path.replace(/^\/Users\/[^/]+/, '~');
    pathEl.textContent = displayPath;
    pathEl.title = path;
  } else {
    pathEl.textContent = name;
    pathEl.title = '';
  }
  pathEl.classList.add('active');
  document.getElementById('clearFolderBtn').style.display = 'inline';
  document.getElementById('savePathHint').textContent = '文件将保存到: ' + (path || name);
}

function displayNoFolder() {
  var pathEl = document.getElementById('folderPath');
  pathEl.textContent = '未选择';
  pathEl.title = '';
  pathEl.classList.remove('active');
  document.getElementById('clearFolderBtn').style.display = 'none';
}

// ── Tab switching ─────────────────────────────────────────────────────────────

function setupTabs() {
  var tabBtns = document.querySelectorAll('.tab-btn');
  tabBtns.forEach(function (btn) {
    btn.addEventListener('click', function () {
      var target = btn.getAttribute('data-tab');
      tabBtns.forEach(function (b) { b.classList.remove('active'); });
      document.querySelectorAll('.tab-panel').forEach(function (p) { p.classList.remove('active'); });
      btn.classList.add('active');
      document.getElementById('tab-' + target).classList.add('active');
      if (target === 'history') {
        loadHistory();
      }
    });
  });
}

// ── Settings functions ────────────────────────────────────────────────────────

function updateModelHint(provider) {
  var hintEl = document.getElementById('modelHint');
  if (hintEl) {
    hintEl.textContent =
      '\u9ED8\u8BA4: ' + (DEFAULT_MODELS[provider] || '');
  }
  updateBaseUrlPlaceholder(provider);
}

function updateBaseUrlPlaceholder(provider) {
  const baseUrlEl = document.getElementById('baseUrl');
  if (!baseUrlEl) return;

  const providerEndpoints = {
    'openai': 'https://api.openai.com/v1',
    'claude': 'https://api.anthropic.com/v1',
    'kimi': 'https://api.moonshot.cn/v1',
    'zhipu': 'https://open.bigmodel.cn/api/paas/v4'
  };

  const defaultEndpoint = providerEndpoints[provider] || '';
  baseUrlEl.placeholder = defaultEndpoint ? `Default: ${defaultEndpoint}` : 'Leave empty to use provider default';
}

function toggleKeyVisibility() {
  const input = document.getElementById('apiKey');
  if (input) {
    input.type = input.type === 'password' ? 'text' : 'password';
  }
}

async function saveSettings() {
  console.log('[popup] saveSettings called');
  try {
    const apiKeyEl = document.getElementById('apiKey');
    const baseUrlEl = document.getElementById('baseUrl');
    const mdModeEl = document.getElementById('mdMode');
    const aiEnabledEl = document.getElementById('aiEnabled');
    const providerEl = document.getElementById('provider');
    const modelEl = document.getElementById('model');
    const langEl = document.getElementById('appLanguage');
    const autoDownloadEl = document.getElementById('autoDownloadMd');

    const apiKeyPlain = apiKeyEl ? apiKeyEl.value.trim() : '';
    const baseUrlInput = baseUrlEl ? baseUrlEl.value.trim() : '';
    const mdMode = mdModeEl ? mdModeEl.value : 'tldr';
    const aiEnabled = aiEnabledEl ? aiEnabledEl.checked : true;

    // Optional validation logic...

    var baseUrl = '';
    if (baseUrlInput) {
      baseUrl = normalizeBaseUrl(baseUrlInput);
      if (!baseUrl) {
        showStatus('Base URL 格式无效', 'error');
        return;
      }
    }

    // Encrypt API key and store in local storage (device-only)
    if (apiKeyPlain) {
      console.log('Encrypting and saving new API Key...');
      var encrypted = await encryptApiKey(apiKeyPlain);
      await chrome.storage.local.set({ encryptedApiKey: encrypted });
      console.log('API Key saved to local storage.');
    } // If empty, we don't clear it immediately to allow "keep existing" logic IF we had a placeholder. 
    // But here user sees empty input if not loaded.
    // If user clears it, we should probably clear storage? 
    // Current logic: if empty, do nothing. Ideally?
    // For now, keep existing logic but safe.

    // Store non-sensitive settings in sync storage.
    var settings = {
      provider: providerEl ? providerEl.value : 'openai',
      language: langEl ? langEl.value : 'zh-CN',
      mdMode: mdMode,
      // model: modelEl ? modelEl.value.trim() : '', // Missing in UI
      baseUrl: baseUrl,
      autoDownloadMd: autoDownloadEl ? autoDownloadEl.checked : true,
      aiEnabled: aiEnabled,
    };

    if (modelEl) settings.model = modelEl.value.trim();

    await chrome.storage.sync.set(settings);

    if (baseUrl) {
      var permissionResult = await ensureOriginPermission(toOriginPattern(baseUrl));
      if (!permissionResult.granted) {
        showStatus('设置已保存，请授权 Base URL 域名访问权限', 'success');
        return;
      }
    }

    showStatus(t('card.saved', document.documentElement.lang), 'success');
  } catch (err) {
    console.error('[popup] saveSettings error:', err);
    showStatus('保存失败: ' + err.message, 'error');
  }
}

function normalizeBaseUrl(value) {
  try {
    var normalizedInput = value;
    if (!/^https?:\/\//i.test(normalizedInput)) {
      normalizedInput = 'https://' + normalizedInput;
    }
    var url = new URL(normalizedInput);
    if (url.protocol !== 'https:' && url.protocol !== 'http:') {
      return '';
    }
    var path = url.pathname.replace(/\/+$/, '');
    return url.origin + path;
  } catch (_) {
    return '';
  }
}

function toOriginPattern(baseUrl) {
  var parsed = new URL(baseUrl);
  return parsed.origin + '/*';
}

function ensureOriginPermission(originPattern) {
  return new Promise(function (resolve) {
    if (!chrome.permissions || !chrome.permissions.contains || !chrome.permissions.request) {
      resolve({ granted: false });
      return;
    }
    chrome.permissions.contains({ origins: [originPattern] }, function (hasPermission) {
      if (chrome.runtime.lastError) { resolve({ granted: false }); return; }
      if (hasPermission) { resolve({ granted: true }); return; }
      chrome.permissions.request({ origins: [originPattern] }, function (granted) {
        if (chrome.runtime.lastError) { resolve({ granted: false }); return; }
        resolve({ granted: !!granted });
      });
    });
  });
}

// Track active status timer so rapid calls don't clear each other prematurely
var statusTimer = null;

function showStatus(message, type) {
  var el = document.getElementById('status');
  if (!el) {
    el = document.createElement('div');
    el.id = 'status';
    el.className = 'status';
    document.body.appendChild(el);
  }

  el.textContent = message;
  el.className = 'status ' + (type || '');
  el.style.display = 'block';

  if (statusTimer) clearTimeout(statusTimer);
  statusTimer = setTimeout(() => {
    el.textContent = '';
    el.className = 'status';
    el.style.display = 'none';
    statusTimer = null;
  }, 3000);
}

// ── Debug info ────────────────────────────────────────────────────────────────

async function loadDebugInfo() {
  var infoEl = document.getElementById('debugInfo');

  try {
    // Gather all debug data in parallel
    var [syncData, localData, nativeResult] = await Promise.all([
      chrome.storage.sync.get({
        provider: 'openai',
        model: '',
        language: 'zh-CN',
        baseUrl: '',
        autoDownloadMd: true,
        mdFolderPath: '',
        aiEnabled: true,
      }),
      chrome.storage.local.get({ lastSave: null, encryptedApiKey: null, encKey: null }),
      // Timeout wrapper for native host ping
      new Promise(resolve => {
        chrome.runtime.sendMessage({ type: 'PING_NATIVE_HOST' })
          .then(resolve)
          .catch(() => resolve(null));
        setTimeout(() => resolve(null), 1000); // 1s timeout
      }),
    ]);

    var nativeStatus = (nativeResult && nativeResult.success)
      ? 'v' + (nativeResult.version || '?')
      : 'not installed';

    var lines = [];
    lines.push('Extension ID: ' + chrome.runtime.id);
    lines.push('Manifest: v' + chrome.runtime.getManifest().version);
    lines.push('Native Host: ' + nativeStatus);
    lines.push('Provider: ' + syncData.provider);
    lines.push('Model: ' + (syncData.model || DEFAULT_MODELS[syncData.provider] || 'default'));
    lines.push('Language: ' + syncData.language);
    if (syncData.baseUrl) {
      lines.push('Base URL: ' + syncData.baseUrl);
    }
    lines.push('Auto Download: ' + (syncData.autoDownloadMd ? 'on' : 'off'));
    lines.push('AI Enabled: ' + (syncData.aiEnabled !== false ? 'on' : 'off'));
    lines.push('Save Path: ' + (syncData.mdFolderPath || '(downloads folder)'));

    // Key status
    lines.push('Enc Key Present: ' + (localData.encKey ? 'Yes' : 'No'));
    lines.push('API Key Stored: ' + (localData.encryptedApiKey ? 'Yes' : 'No'));

    if (localData.lastSave) {
      var ls = localData.lastSave;
      var timeStr = new Date(ls.timestamp).toLocaleString();
      var statusStr = ls.success ? 'success' : ('failed: ' + (ls.error || 'unknown'));
      lines.push('Last Save: ' + timeStr + ' — ' + statusStr);
      if (ls.path) {
        lines.push('Last Path: ' + ls.path);
      }
    } else {
      lines.push('Last Save: (none)');
    }

    infoEl.textContent = lines.join('\n');
  } catch (err) {
    infoEl.textContent = 'Error loading debug info: ' + err.message;
  }
}

async function copyDebugInfo() {
  var infoEl = document.getElementById('debugInfo');
  var btn = document.getElementById('copyDebugBtn');
  try {
    await navigator.clipboard.writeText(infoEl.textContent);
    btn.textContent = '已复制';
    btn.classList.add('copied');
    setTimeout(function () {
      btn.textContent = '复制调试信息';
      btn.classList.remove('copied');
    }, 1500);
  } catch (_) {
    // Fallback: select text for manual copy
    var range = document.createRange();
    range.selectNodeContents(infoEl);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
  }
}

// ── View Management (Bottom Navigation) ───────────────────────────────────

function setupTabs() {
  const navItems = document.querySelectorAll('.nav-item');
  navItems.forEach(item => {
    item.addEventListener('click', () => {
      // Remove active from all
      navItems.forEach(nav => nav.classList.remove('active'));
      document.querySelectorAll('.view').forEach(view => view.classList.remove('active'));

      // Add active to current
      item.classList.add('active');
      const targetId = item.getAttribute('data-target');
      document.getElementById(targetId).classList.add('active');
    });
  });

  // "View All" button on dashboard
  const viewAllBtn = document.getElementById('viewAllHistory');
  if (viewAllBtn) {
    viewAllBtn.addEventListener('click', () => {
      // Trigger click on history nav item
      document.querySelector('.nav-item[data-target="view-history"]').click();
    });
  }
}

// ── History search with debounce ──────────────────────────────────────────
const searchInput = document.getElementById('historySearch');
if (searchInput) {
  let searchTimeout;
  searchInput.addEventListener('input', (e) => {
    clearTimeout(searchTimeout);
    searchTimeout = setTimeout(() => {
      filterHistory(e.target.value.toLowerCase());
    }, 300); // 300ms debounce
  });

  // Clear search on Escape
  searchInput.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') {
      searchInput.value = '';
      filterHistory('');
    }
  });
}

// ── Navigation ─────────────────────────────────────────────────────────────

function initDashboard() {
  chrome.storage.local.get({ history: [] }, function (data) {
    const history = data.history || [];

    // Update stats
    const totalEl = document.getElementById('stat-total');
    if (totalEl) totalEl.textContent = history.length;

    // Calculate today's saved
    const today = new Date().toDateString();
    const todayCount = history.filter(item => new Date(item.timestamp).toDateString() === today).length;
    const todayEl = document.getElementById('stat-today');
    if (todayEl) todayEl.textContent = todayCount;

    // Render recent list (max 3 items)
    const recentList = document.getElementById('dashboard-recent-list');
    if (recentList) {
      recentList.innerHTML = '';
      const lang = document.documentElement.lang || 'zh-CN';

      if (history.length === 0) {
        recentList.innerHTML = `<div class="empty-state-mini">${t('recent.empty', lang)}</div>`;
        return;
      }

      // Get last 3 items, reversed
      const recentItems = history.slice().reverse().slice(0, 3);

      recentItems.forEach(item => {
        const el = document.createElement('div');
        el.className = 'history-card';

        const dateStr = new Date(item.timestamp).toLocaleDateString();

        el.innerHTML = `
          <div class="history-item-header">
            <span class="history-author">${escapeHtml(item.author || 'Unknown')}</span>
            <span class="history-time">${dateStr}</span>
          </div>
        `;
        recentList.appendChild(el);
      });
    }
  });
}

// ── Footer Logic ──────────────────────────────────────────────────────────

function initFooter() {
  var manifest = chrome.runtime.getManifest();
  var versionEl = document.getElementById('versionLabel');
  if (versionEl) {
    versionEl.textContent = 'v' + manifest.version;
  }
  checkForUpdate(manifest.version);
}

// Compare the local extension version against the latest GitHub release.
// Uses a 24-hour cache in chrome.storage.local to avoid hitting the API
// every time the popup opens.
async function checkForUpdate(currentVersion) {
  try {
    var cacheData = await chrome.storage.local.get('updateCheck');
    var cache = cacheData.updateCheck;
    var now = Date.now();

    // Use cached result if checked within the last 24 hours
    if (cache && cache.checkedAt && (now - cache.checkedAt) < 24 * 60 * 60 * 1000) {
      if (cache.latestVersion && isNewerVersion(cache.latestVersion, currentVersion)) {
        showUpdateBadge(cache.latestVersion);
      }
      return;
    }

    var res = await fetch(
      'https://api.github.com/repos/' + UPDATE_CHECK_REPO + '/releases/latest',
      { headers: { Accept: 'application/vnd.github.v3+json' } }
    );
    if (!res.ok) return;

    var data = await res.json();
    var latestTag = (data.tag_name || '').replace(/^v/, '');
    if (!latestTag) return;

    // Cache the result for 24 hours
    await chrome.storage.local.set({
      updateCheck: { latestVersion: latestTag, checkedAt: now },
    });

    if (isNewerVersion(latestTag, currentVersion)) {
      showUpdateBadge(latestTag);
    }
  } catch (_) {
    // Network error or API failure — silently ignore
  }
}

// Simple semver comparison: returns true if remote > local
function isNewerVersion(remote, local) {
  var r = remote.split('.').map(Number);
  var l = local.split('.').map(Number);
  for (var i = 0; i < 3; i++) {
    if ((r[i] || 0) > (l[i] || 0)) return true;
    if ((r[i] || 0) < (l[i] || 0)) return false;
  }
  return false;
}

function showUpdateBadge(version) {
  var badge = document.getElementById('updateBadge');
  badge.textContent = 'v' + version + ' 可用';
  badge.style.display = 'inline-block';
}

// ── Install script generator ──────────────────────────────────────────────────

// Generate a self-contained install script with the extension ID baked in,
// download it, then show the user a one-liner to run in Terminal.
function downloadInstallScript() {
  var extId = chrome.runtime.id;

  // The Python native messaging host script, embedded inline.
  // Handles ping, pick_folder (macOS osascript), and write_file actions.
  var pythonScript = [
    '#!/usr/bin/env python3',
    '"""Native messaging host for btl extension."""',
    'import json, os, struct, subprocess, sys',
    '',
    'def read_msg():',
    '    raw = sys.stdin.buffer.read(4)',
    '    if len(raw) < 4: return None',
    '    return json.loads(sys.stdin.buffer.read(struct.unpack("<I", raw)[0]))',
    '',
    'def send_msg(m):',
    '    d = json.dumps(m, ensure_ascii=False).encode("utf-8")',
    '    sys.stdout.buffer.write(struct.pack("<I", len(d)) + d)',
    '    sys.stdout.buffer.flush()',
    '',
    'def pick_folder():',
    '    try:',
    '        r = subprocess.run(["osascript", "-e",',
    '            \'POSIX path of (choose folder with prompt "选择 Markdown 保存文件夹")\'],',
    '            capture_output=True, text=True, timeout=120)',
    '        if r.returncode == 0 and r.stdout.strip():',
    '            p = r.stdout.strip().rstrip("/")',
    '            return {"success": True, "path": p, "name": os.path.basename(p)}',
    '        return {"success": False, "error": "cancelled"}',
    '    except Exception as e:',
    '        return {"success": False, "error": str(e)}',
    '',
    'def validate_path(fp):',
    '    if "\\x00" in fp: return None, "path contains null byte"',
    '    parts = fp.replace("\\\\", "/").split("/")',
    '    if ".." in parts: return None, "path contains .."',
    '    expanded = os.path.expanduser(fp)',
    '    resolved = os.path.realpath(expanded)',
    '    home = os.path.expanduser("~")',
    '    if not resolved.startswith(home + os.sep) and resolved != home:',
    '        return None, "path outside home"',
    '    return resolved, None',
    '',
    'def write_file(fp, content):',
    '    try:',
    '        resolved, err = validate_path(fp)',
    '        if err: return {"success": False, "error": err}',
    '        d = os.path.dirname(resolved)',
    '        if d: os.makedirs(d, exist_ok=True)',
    '        base, ext = os.path.splitext(resolved)',
    '        final, c = resolved, 0',
    '        while os.path.exists(final) and c < 100:',
    '            c += 1; final = f"{base} ({c}){ext}"',
    '        with open(final, "w", encoding="utf-8") as f: f.write(content)',
    '        return {"success": True, "path": final}',
    '    except Exception as e:',
    '        return {"success": False, "error": str(e)}',
    '',
    'def main():',
    '    m = read_msg()',
    '    if not m: return',
    '    a = m.get("action", "")',
    '    if a == "ping": send_msg({"success": True, "version": "1.2.0"})',
    '    elif a == "pick_folder": send_msg(pick_folder())',
    '    elif a == "write_file":',
    '        p, c = m.get("path", ""), m.get("content", "")',
    '        send_msg(write_file(p, c) if p else {"success": False, "error": "no path"})',
    '    else: send_msg({"success": False, "error": f"unknown: {a}"})',
    '',
    'if __name__ == "__main__": main()',
  ].join('\n');

  // Self-contained bash install script
  var script = '#!/bin/bash\n'
    + '# One-click installer for btl Native Helper\n'
    + '# Extension ID: ' + extId + '\n'
    + 'set -e\n'
    + '\n'
    + 'INSTALL_DIR="$HOME/.btl-native-host"\n'
    + 'HOST_NAME="com.btl.file_writer"\n'
    + 'EXT_ID="' + extId + '"\n'
    + '\n'
    + 'echo "Installing Native Helper..."\n'
    + 'mkdir -p "$INSTALL_DIR"\n'
    + '\n'
    + "cat > \"$INSTALL_DIR/btl_file_writer.py\" << 'PYTHON_EOF'\n"
    + pythonScript + '\n'
    + 'PYTHON_EOF\n'
    + '\n'
    + 'chmod +x "$INSTALL_DIR/btl_file_writer.py"\n'
    + '\n'
    + 'BROWSER_DIRS=(\n'
    + '  "$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"\n'
    + '  "$HOME/Library/Application Support/Google/Chrome Beta/NativeMessagingHosts"\n'
    + '  "$HOME/Library/Application Support/Google/Chrome Canary/NativeMessagingHosts"\n'
    + '  "$HOME/Library/Application Support/Chromium/NativeMessagingHosts"\n'
    + '  "$HOME/Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts"\n'
    + '  "$HOME/Library/Application Support/Microsoft Edge/NativeMessagingHosts"\n'
    + ')\n'
    + '\n'
    + 'count=0\n'
    + 'for dir in "${BROWSER_DIRS[@]}"; do\n'
    + '  parent="$(dirname "$dir")"\n'
    + '  if [ -d "$parent" ]; then\n'
    + '    mkdir -p "$dir"\n'
    + '    cat > "$dir/$HOST_NAME.json" << MANIFEST_EOF\n'
    + '{\n'
    + '  "name": "$HOST_NAME",\n'
    + '  "description": "File writer for BTL extension",\n'
    + '  "path": "$INSTALL_DIR/btl_file_writer.py",\n'
    + '  "type": "stdio",\n'
    + '  "allowed_origins": ["chrome-extension://$EXT_ID/"]\n'
    + '}\n'
    + 'MANIFEST_EOF\n'
    + '    echo "  Installed: $dir"\n'
    + '    count=$((count + 1))\n'
    + '  fi\n'
    + 'done\n'
    + '\n'
    + 'if [ "$count" -eq 0 ]; then\n'
    + '  echo "No browser detected."; exit 1\n'
    + 'fi\n'
    + '\n'
    + 'echo ""\n'
    + 'echo "Done! Please restart your browser."\n';

  var dataUrl = 'data:text/plain;charset=utf-8,' + encodeURIComponent(script);
  chrome.downloads.download({
    url: dataUrl,
    filename: 'install-btl-native.sh',
    saveAs: false,
    conflictAction: 'overwrite',
  });

  // Show the run instruction
  document.getElementById('nativeSetupStep2').style.display = 'block';
}


// ── History functions ─────────────────────────────────────────────────────────

async function loadHistory() {
  var result = await chrome.storage.local.get({ history: [] });
  var history = result.history;

  var listEl = document.getElementById('historyList');
  var emptyEl = document.getElementById('historyEmpty');
  var clearBtn = document.getElementById('clearHistoryBtn');

  listEl.textContent = '';

  // Clean up existing empty message if any (it might be duplicated if we are not careful, 
  // but here we are clearing listEl, while emptyEl is a sibling? 
  // In popup.html, historyEmpty is a sibling of historyList.

  if (history.length === 0) {
    if (emptyEl) emptyEl.style.display = 'flex';
    if (clearBtn) clearBtn.style.display = 'none';
    return;
  }

  if (emptyEl) emptyEl.style.display = 'none';
  if (clearBtn) clearBtn.style.display = 'block';

  // Build all history items in a DocumentFragment for a single DOM reflow
  var fragment = document.createDocumentFragment();
  const lang = document.documentElement.lang || 'zh-CN';

  history.forEach(function (entry) {
    var item = document.createElement('div');
    item.className = 'history-item';

    var header = document.createElement('div');
    header.className = 'history-item-header';

    var authorSpan = document.createElement('span');
    authorSpan.className = 'history-author';
    authorSpan.textContent = entry.author || 'Unknown';

    var timeSpan = document.createElement('span');
    timeSpan.className = 'history-time';
    timeSpan.textContent = formatRelativeTime(entry.timestamp);

    header.appendChild(authorSpan);
    header.appendChild(timeSpan);

    var preview = document.createElement('div');
    preview.className = 'history-preview';
    preview.textContent = entry.tweetPreview || '';

    item.appendChild(header);
    item.appendChild(preview);

    var actions = document.createElement('div');
    actions.className = 'history-actions';

    if (entry.tweetUrl) {
      var link = document.createElement('a');
      link.href = entry.tweetUrl;
      link.target = '_blank';
      link.rel = 'noopener';
      link.className = 'history-link';
      link.textContent = t('card.viewOriginal', lang); // Localized
      actions.appendChild(link);
    }

    // Tags display and management
    var tagsContainer = document.createElement('div');
    tagsContainer.className = 'history-tags';

    if (entry.tags && entry.tags.length > 0) {
      entry.tags.forEach(tag => {
        var tagChip = document.createElement('span');
        tagChip.className = 'tag-chip';
        tagChip.textContent = tag;

        var removeBtn = document.createElement('button');
        removeBtn.className = 'tag-remove';
        removeBtn.textContent = '×';
        removeBtn.addEventListener('click', () => removeTag(entry.id, tag));

        tagChip.appendChild(removeBtn);
        tagsContainer.appendChild(tagChip);
      });
    }

    // Add tag button
    var addTagBtn = document.createElement('button');
    addTagBtn.className = 'tag-add-btn';
    addTagBtn.textContent = '+ Tag';
    addTagBtn.addEventListener('click', () => showTagInput(entry.id, tagsContainer));
    tagsContainer.appendChild(addTagBtn);

    item.appendChild(tagsContainer);

    // Only show TLDR expand/collapse when there is TLDR content
    if (entry.tldr) {
      var tldrWrap = document.createElement('div');
      tldrWrap.className = 'history-tldr collapsed';

      var tldrContent = document.createElement('div');
      tldrContent.className = 'history-tldr-text';
      tldrContent.textContent = entry.tldr;
      tldrWrap.appendChild(tldrContent);

      var toggleBtn = document.createElement('button');
      toggleBtn.className = 'history-toggle';
      const txtExpand = lang === 'zh-CN' ? '展开摘要' : 'Expand Summary';
      const txtCollapse = lang === 'zh-CN' ? '收起摘要' : 'Collapse Summary';

      toggleBtn.textContent = txtExpand;
      toggleBtn.addEventListener('click', function () {
        var isCollapsed = tldrWrap.classList.contains('collapsed');
        if (isCollapsed) {
          tldrWrap.classList.remove('collapsed');
          toggleBtn.textContent = txtCollapse;
        } else {
          tldrWrap.classList.add('collapsed');
          toggleBtn.textContent = txtExpand;
        }
      });

      item.appendChild(tldrWrap);
      actions.appendChild(toggleBtn);
    }

    item.appendChild(actions);
    fragment.appendChild(item);
  });

  listEl.appendChild(fragment);
}

// Filter history based on search query
function filterHistory(query) {
  const items = document.querySelectorAll('.history-item');
  let visibleCount = 0;

  items.forEach(item => {
    if (!query) {
      item.style.display = 'block';
      visibleCount++;
      // Remove any existing highlights
      const highlighted = item.querySelectorAll('.highlight');
      highlighted.forEach(el => {
        el.outerHTML = el.textContent;
      });
      return;
    }

    const author = item.querySelector('.history-author')?.textContent.toLowerCase() || '';
    const preview = item.querySelector('.history-preview')?.textContent.toLowerCase() || '';
    const tldr = item.querySelector('.history-tldr-text')?.textContent.toLowerCase() || '';

    const matches = author.includes(query) || preview.includes(query) || tldr.includes(query);

    if (matches) {
      item.style.display = 'block';
      visibleCount++;
      // Highlight matches
      highlightText(item, query);
    } else {
      item.style.display = 'none';
    }
  });

  // Update result count
  updateSearchResultCount(visibleCount, items.length);
}

// Highlight search matches
function highlightText(container, query) {
  if (!query) return;

  const elements = container.querySelectorAll('.history-author, .history-preview, .history-tldr-text');
  elements.forEach(el => {
    const text = el.textContent;
    const lowerText = text.toLowerCase();
    const index = lowerText.indexOf(query);

    if (index !== -1) {
      const before = text.substring(0, index);
      const match = text.substring(index, index + query.length);
      const after = text.substring(index + query.length);
      el.innerHTML = `${escapeHtml(before)}<mark class="search-highlight">${escapeHtml(match)}</mark>${escapeHtml(after)}`;
    }
  });
}

// Update search result count display
function updateSearchResultCount(visible, total) {
  let countEl = document.getElementById('searchResultCount');
  if (!countEl) {
    countEl = document.createElement('div');
    countEl.id = 'searchResultCount';
    countEl.className = 'search-result-count';
    const searchBar = document.querySelector('.search-bar');
    if (searchBar) {
      searchBar.appendChild(countEl);
    }
  }

  if (visible < total) {
    countEl.textContent = `${visible} / ${total}`;
    countEl.style.display = 'block';
  } else {
    countEl.style.display = 'none';
  }
}

// ── Utility Functions ─────────────────────────────────────────────────────────

function escapeHtml(text) {
  var div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

// Two-click confirmation: first click shows "确定清空？", second click actually clears.
// confirm() is blocked in Chrome extension popups, so we use inline confirmation instead.
var clearHistoryPending = false;
var clearHistoryTimer = null;

function clearHistory() {
  var btn = document.getElementById('clearHistoryBtn');
  const lang = document.documentElement.lang || 'zh-CN';

  if (!clearHistoryPending) {
    // First click — ask for confirmation
    clearHistoryPending = true;
    btn.textContent = t('history.confirmClear', lang);
    btn.classList.add('confirming');
    // Reset after 3 seconds if user doesn't confirm
    clearHistoryTimer = setTimeout(function () {
      clearHistoryPending = false;
      btn.textContent = t('history.clear', lang);
      btn.classList.remove('confirming');
    }, 3000);
    return;
  }

  // Second click — actually clear
  clearTimeout(clearHistoryTimer);
  clearHistoryPending = false;
  btn.textContent = t('history.clear', lang);
  btn.classList.remove('confirming');
  chrome.storage.local.set({ history: [] }).then(function () {
    loadHistory();
    showStatus(lang === 'zh-CN' ? '历史记录已清空' : 'History cleared', 'success');
  });
}

// ── Relative time formatting ─────────────────────────────────────────────────

function formatRelativeTime(timestamp) {
  var now = Date.now();
  var diff = now - timestamp;
  var seconds = Math.floor(diff / 1000);
  var minutes = Math.floor(seconds / 60);
  var hours = Math.floor(minutes / 60);
  var days = Math.floor(hours / 24);

  const lang = document.documentElement.lang || 'zh-CN';
  const isEn = lang !== 'zh-CN';

  if (seconds < 60) return isEn ? 'Just now' : '刚刚';
  if (minutes < 60) return isEn ? `${minutes}m ago` : `${minutes} 分钟前`;
  if (hours < 24) return isEn ? `${hours}h ago` : `${hours} 小时前`;
  if (days < 30) return isEn ? `${days}d ago` : `${days} 天前`;

  var d = new Date(timestamp);
  return (d.getMonth() + 1) + '/' + d.getDate();
}
// ── Export/Import History Functions ──────────────────────────────────────────

// Show export format selection dialog
async function showExportDialog() {
  const result = await chrome.storage.local.get({ history: [] });
  const history = result.history;

  if (history.length === 0) {
    showStatus('没有历史记录可导出', 'error');
    return;
  }

  // Create a simple dialog
  const dialog = document.createElement('div');
  dialog.className = 'export-dialog';
  dialog.innerHTML = `
    <div class="export-dialog-content">
      <h3>选择导出格式</h3>
      <div class="export-options">
        <button class="export-option-btn" data-format="json">
          <span>📄</span>
          <div>
            <strong>JSON</strong>
            <small>完整数据，可重新导入</small>
          </div>
        </button>
        <button class="export-option-btn" data-format="markdown">
          <span>📝</span>
          <div>
            <strong>Markdown</strong>
            <small>可读格式，适合分享</small>
          </div>
        </button>
        <button class="export-option-btn" data-format="csv">
          <span>📊</span>
          <div>
            <strong>CSV</strong>
            <small>表格格式，适合分析</small>
          </div>
        </button>
      </div>
      <button class="export-cancel-btn">取消</button>
    </div>
  `;

  document.body.appendChild(dialog);

  // Handle format selection
  dialog.querySelectorAll('.export-option-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const format = btn.dataset.format;
      exportHistory(history, format);
      document.body.removeChild(dialog);
    });
  });

  dialog.querySelector('.export-cancel-btn').addEventListener('click', () => {
    document.body.removeChild(dialog);
  });
}

// Export history in selected format
function exportHistory(history, format) {
  let content, filename, mimeType;

  const timestamp = new Date().toISOString().split('T')[0];

  switch (format) {
    case 'json':
      content = JSON.stringify(history, null, 2);
      filename = `antimark-history-${timestamp}.json`;
      mimeType = 'application/json';
      break;

    case 'markdown':
      content = generateMarkdownExport(history);
      filename = `antimark-history-${timestamp}.md`;
      mimeType = 'text/markdown';
      break;

    case 'csv':
      content = generateCSVExport(history);
      filename = `antimark-history-${timestamp}.csv`;
      mimeType = 'text/csv';
      break;
  }

  // Create download
  const blob = new Blob([content], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);

  showStatus(`已导出 ${history.length} 条记录`, 'success');
}

// Generate Markdown export
function generateMarkdownExport(history) {
  let md = `# AntiMark History Export\n\n`;
  md += `Exported: ${new Date().toLocaleString()}\n`;
  md += `Total Items: ${history.length}\n\n`;
  md += `---\n\n`;

  history.forEach((entry, index) => {
    md += `## ${index + 1}. ${entry.author || 'Unknown'}\n\n`;
    md += `**Date**: ${new Date(entry.timestamp).toLocaleString()}\n\n`;

    if (entry.tweetUrl) {
      md += `**Link**: ${entry.tweetUrl}\n\n`;
    }

    if (entry.tweetPreview) {
      md += `**Tweet**:\n> ${entry.tweetPreview}\n\n`;
    }

    if (entry.tldr) {
      md += `**Summary**:\n${entry.tldr}\n\n`;
    }

    md += `---\n\n`;
  });

  return md;
}

// Generate CSV export
function generateCSVExport(history) {
  const headers = ['Date', 'Author', 'Tweet', 'Summary', 'URL'];
  let csv = headers.join(',') + '\n';

  history.forEach(entry => {
    const row = [
      new Date(entry.timestamp).toISOString(),
      escapeCSV(entry.author || ''),
      escapeCSV(entry.tweetPreview || ''),
      escapeCSV(entry.tldr || ''),
      entry.tweetUrl || ''
    ];
    csv += row.join(',') + '\n';
  });

  return csv;
}

// Escape CSV fields
function escapeCSV(str) {
  if (!str) return '""';
  str = str.replace(/"/g, '""');
  return `"${str}"`;
}

// Import history from file
async function importHistory() {
  const input = document.createElement('input');
  input.type = 'file';
  input.accept = '.json';

  input.addEventListener('change', async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    try {
      const text = await file.text();
      const imported = JSON.parse(text);

      // Validate data
      if (!Array.isArray(imported)) {
        throw new Error('Invalid format: expected array');
      }

      // Get existing history
      const result = await chrome.storage.local.get({ history: [] });
      const existing = result.history;

      // Merge and deduplicate
      const merged = [...existing];
      let newCount = 0;

      imported.forEach(item => {
        // Check if already exists (by tweetUrl and timestamp)
        const exists = existing.some(e =>
          e.tweetUrl === item.tweetUrl && e.timestamp === item.timestamp
        );

        if (!exists) {
          merged.push(item);
          newCount++;
        }
      });

      // Sort by timestamp (newest first)
      merged.sort((a, b) => b.timestamp - a.timestamp);

      // Save
      await chrome.storage.local.set({ history: merged });

      // Reload UI
      loadHistory();
      initDashboard();

      showStatus(`成功导入 ${newCount} 条新记录`, 'success');
    } catch (err) {
      console.error('Import error:', err);
      showStatus('导入失败: ' + err.message, 'error');
    }
  });

  input.click();
}
// ── Tag Management Functions ──────────────────────────────────────────────────

// Show tag input for adding new tag
function showTagInput(entryId, container) {
  // Check if input already exists
  if (container.querySelector('.tag-input')) return;

  const input = document.createElement('input');
  input.type = 'text';
  input.className = 'tag-input';
  input.placeholder = 'Enter tag...';
  input.maxLength = 20;

  const addBtn = container.querySelector('.tag-add-btn');
  container.insertBefore(input, addBtn);
  input.focus();

  const saveTag = async () => {
    const tag = input.value.trim().toLowerCase();
    if (!tag) {
      input.remove();
      return;
    }

    await addTag(entryId, tag);
    input.remove();
    loadHistory(); // Reload to show new tag
  };

  input.addEventListener('keydown', (e) => {
    if (e.key === 'Enter') {
      saveTag();
    } else if (e.key === 'Escape') {
      input.remove();
    }
  });

  input.addEventListener('blur', () => {
    setTimeout(() => input.remove(), 200);
  });
}

// Add tag to entry
async function addTag(entryId, tag) {
  const result = await chrome.storage.local.get({ history: [] });
  const history = result.history;

  const entry = history.find(e => e.id === entryId);
  if (!entry) return;

  if (!entry.tags) entry.tags = [];

  // Avoid duplicates
  if (!entry.tags.includes(tag)) {
    entry.tags.push(tag);
    await chrome.storage.local.set({ history });
    showStatus(`Tag "${tag}" added`, 'success');
  }
}

// Remove tag from entry
async function removeTag(entryId, tag) {
  const result = await chrome.storage.local.get({ history: [] });
  const history = result.history;

  const entry = history.find(e => e.id === entryId);
  if (!entry || !entry.tags) return;

  entry.tags = entry.tags.filter(t => t !== tag);
  await chrome.storage.local.set({ history });

  loadHistory(); // Reload to update UI
  showStatus(`Tag "${tag}" removed`, 'success');
}

// Get all unique tags from history
async function getAllTags() {
  const result = await chrome.storage.local.get({ history: [] });
  const history = result.history;

  const tagsSet = new Set();
  history.forEach(entry => {
    if (entry.tags) {
      entry.tags.forEach(tag => tagsSet.add(tag));
    }
  });

  return Array.from(tagsSet).sort();
}

// Filter history by tag
function filterByTag(tag) {
  const items = document.querySelectorAll('.history-item');

  items.forEach(item => {
    const tags = Array.from(item.querySelectorAll('.tag-chip'))
      .map(chip => chip.textContent.replace('×', '').trim());

    if (!tag || tags.includes(tag)) {
      item.style.display = 'block';
    } else {
      item.style.display = 'none';
    }
  });
}
