import { Posts, Groups, Jobs, Logs, Campaigns, Media, Discoveries, Comments } from '../lib/repo.js';
import { DEFAULTS } from '../lib/delays.js';
import { setSetting, getSetting } from '../lib/db.js';
import { getSession, login, logout, logoutEverywhere, verifySession, verifyOtp } from '../lib/auth.js';
import { getGeminiKey, saveGeminiKey, clearGeminiKey, testGeminiKey } from '../lib/gemini.js';
import { SYNC } from '../lib/config.js';
import { obLog } from '../lib/logger.js';

obLog.setSource('ext-popup');
obLog.attachGlobalHandlers();
obLog.event('popup_opened');

// === Settings 2-pane navigation ===
// Right column = list of categories; left column = active pane.
// Last active pane is remembered in chrome.storage.local.
function initSettingsNav() {
  const nav = document.getElementById('settings-nav');
  if (!nav) return;
  // Restore last-active pane (default: 'ai')
  let pending = 'ai';
  try {
    chrome.storage.local.get('settingsActivePane', (r) => {
      activatePane(r.settingsActivePane || pending);
    });
  } catch { activatePane(pending); }

  function activatePane(pane) {
    nav.querySelectorAll('.settings-nav-btn').forEach(b =>
      b.classList.toggle('active', b.dataset.pane === pane));
    document.querySelectorAll('.settings-pane').forEach(p =>
      p.classList.toggle('active', p.dataset.pane === pane));
    try { chrome.storage.local.set({ settingsActivePane: pane }); } catch {}
    // Scroll content area to top — feels like switching pages, not scrolling
    const content = document.querySelector('.settings-content');
    if (content) content.scrollIntoView({ block: 'start', behavior: 'instant' });
  }
  nav.addEventListener('click', (e) => {
    const btn = e.target.closest('.settings-nav-btn');
    if (!btn) return;
    activatePane(btn.dataset.pane);
  });
}
document.addEventListener('DOMContentLoaded', initSettingsNav);
// If DOM already parsed, run immediately.
if (document.readyState !== 'loading') initSettingsNav();

// ════════════════════════════════════════════════════════════════════
// Self-test panel — shows on first popup open after install. Gives the
// user instant confidence that everything is wired right (or surfaces
// what's broken with a clear "fix it" pointer).
// ════════════════════════════════════════════════════════════════════
async function runSelfTest() {
  const SHOWN_KEY = 'organicai.selfTestShown';
  const panel = document.getElementById('self-test');
  if (!panel) return;

  // Show first time + first day → after that, only if there's an error
  const lastShown = parseInt(localStorage.getItem(SHOWN_KEY) || '0');
  const oneDayMs = 24 * 3600 * 1000;
  const shouldAlwaysShow = !lastShown || (Date.now() - lastShown > 7 * oneDayMs);

  panel.hidden = false;
  let anyError = false;

  const setRow = (check, state, info = '') => {
    const row = panel.querySelector(`[data-check="${check}"]`);
    if (!row) return;
    row.classList.remove('ok', 'warn', 'err');
    if (state) row.classList.add(state);
    const infoEl = row.querySelector('.info');
    if (infoEl) infoEl.textContent = info;
    if (state === 'err') anyError = true;
  };

  // Helper: fetch with auth + worker URL
  const callWorker = async (path) => {
    try {
      const { SYNC } = await import('../lib/config.js');
      const { getSession } = await import('../lib/auth.js');
      const { token } = await getSession();
      if (!token) return { needsLogin: true };
      const t0 = performance.now();
      const r = await fetch(SYNC.endpoint + path, {
        headers: { 'X-Session-Token': token },
      });
      const ms = Math.round(performance.now() - t0);
      if (!r.ok) return { ok: false, status: r.status, ms };
      const j = await r.json();
      return { ok: true, data: j, ms };
    } catch (e) {
      return { ok: false, error: String(e?.message || e) };
    }
  };

  // 1. Server connection
  try {
    const t0 = performance.now();
    const { SYNC } = await import('../lib/config.js');
    const r = await fetch(SYNC.endpoint + '/health');
    const ms = Math.round(performance.now() - t0);
    if (r.ok) setRow('server', 'ok', `${ms}ms`);
    else setRow('server', 'err', `HTTP ${r.status}`);
  } catch {
    setRow('server', 'err', 'אין רשת');
  }

  // 2. Session
  const meRes = await callWorker('/api/v1/me');
  if (meRes.needsLogin) {
    setRow('session', 'warn', 'לא מחובר — התחבר למטה');
  } else if (meRes.ok) {
    setRow('session', 'ok', meRes.data?.username || '✓');
  } else {
    setRow('session', 'err', meRes.error || `HTTP ${meRes.status}`);
  }

  // 3. Sync — last sync time from localStorage (rough indicator)
  const lastSync = parseInt(localStorage.getItem('organicai.lastSync') || '0');
  if (!lastSync) setRow('sync', 'warn', 'עוד לא היה');
  else {
    const diffMin = Math.floor((Date.now() - lastSync) / 60000);
    setRow('sync', diffMin < 5 ? 'ok' : 'warn', diffMin < 1 ? 'כעת' : `לפני ${diffMin} דק׳`);
  }

  // 4. AI provider / trial
  if (meRes.ok) {
    const [provRes, trialRes] = await Promise.all([
      callWorker('/api/v1/ai/providers'),
      callWorker('/api/v1/ai/trial'),
    ]);
    const def = provRes.ok && (provRes.data?.providers || []).find(p => p.is_default && p.is_active);
    if (def) {
      setRow('ai', 'ok', `${def.label || def.provider}`);
    } else if (trialRes.ok) {
      const left = trialRes.data?.calls_remaining ?? 50;
      if (left > 0) setRow('ai', 'ok', `🎁 ${left}/50 ניסיון`);
      else setRow('ai', 'warn', '🎁 נגמר — הוסף ספק');
    } else {
      setRow('ai', 'warn', 'לא נקבע');
    }
  } else {
    setRow('ai', 'warn', '⏸ דורש התחברות');
  }

  // Update title
  const spinner = document.getElementById('self-test-spinner');
  const title = panel.querySelector('.self-test__title strong');
  if (spinner) spinner.textContent = anyError ? '⚠' : '✅';
  if (title) title.textContent = anyError ? 'יש בעיה — הצביעו לי איפה' : 'הכל מוכן ⚡';

  // Auto-collapse the panel after 4 seconds if everything is OK
  if (!anyError && !shouldAlwaysShow) {
    setTimeout(() => { panel.hidden = true; }, 4000);
  }

  // Close button
  const closeBtn = document.getElementById('self-test-close');
  if (closeBtn) closeBtn.addEventListener('click', () => {
    panel.hidden = true;
    localStorage.setItem(SHOWN_KEY, String(Date.now()));
  });
}
document.addEventListener('DOMContentLoaded', () => { setTimeout(runSelfTest, 300); });
if (document.readyState !== 'loading') setTimeout(runSelfTest, 300);

const $ = (id) => document.getElementById(id);

// ===== Context detection — which platform is the active tab on? =====
// Shows a banner at top of popup so user knows "we noticed you're on X".
const PLATFORM_DEF = {
  facebook:  { label: 'Facebook',     emoji: '📘', host: /(^|\.)facebook\.com$/i },
  linkedin:  { label: 'LinkedIn',     emoji: '💼', host: /(^|\.)linkedin\.com$/i },
  twitter:   { label: 'X / Twitter',  emoji: '𝕏',  host: /(^|\.)(twitter|x)\.com$/i },
  reddit:    { label: 'Reddit',       emoji: '🤖', host: /(^|\.)reddit\.com$/i },
  instagram: { label: 'Instagram',    emoji: '📷', host: /(^|\.)instagram\.com$/i },
};

async function detectActivePlatform() {
  try {
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
    if (!tab?.url) return null;
    const u = new URL(tab.url);
    for (const [key, def] of Object.entries(PLATFORM_DEF)) {
      if (def.host.test(u.hostname)) return { key, ...def, url: tab.url };
    }
    return null;
  } catch { return null; }
}

async function renderContextBanner() {
  const banner = $('context-banner');
  if (!banner) return;
  const p = await detectActivePlatform();
  if (!p) {
    banner.innerHTML = `
      <div class="ctx-row ctx-row--idle">
        <span class="ctx-dot"></span>
        <span class="ctx-text">לא זוהתה פלטפורמה פעילה</span>
        <span class="ctx-hint">פתח טאב של מדיה חברתית להפעלת פעולות מהירות</span>
      </div>`;
    return;
  }
  // Detect if user is on their own LinkedIn profile page (/in/<handle>)
  const onLiProfile = p.key === 'linkedin' && /\/in\//.test(p.url || '');

  banner.innerHTML = `
    <div class="ctx-row ctx-row--live" data-platform="${p.key}">
      <span class="ctx-dot ctx-dot--live"></span>
      <span class="ctx-emoji" aria-hidden="true">${p.emoji}</span>
      <span class="ctx-text">מחובר ל-<strong>${p.label}</strong></span>
      ${onLiProfile ? '<button class="ctx-action" data-ctx-action="audit-profile" style="background:var(--success, #10b981); color:#fff; border-color:transparent;">🔍 בדוק את הפרופיל</button>' : ''}
      <button class="ctx-action" data-ctx-action="campaign">קמפיין חדש</button>
      <button class="ctx-action ghost" data-ctx-action="discover">חפש קבוצות</button>
    </div>
    <div id="profile-audit-result" style="display:none; margin-top:12px;"></div>`;

  banner.querySelectorAll('[data-ctx-action]').forEach(btn => {
    btn.addEventListener('click', async () => {
      const act = btn.dataset.ctxAction;
      if (act === 'campaign') {
        setSetting('newCampaignPlatform', p.key);
        switchTab('campaigns');
      }
      if (act === 'discover') {
        setSetting('discoverPlatform', p.key);
        switchTab('groups');
      }
      if (act === 'audit-profile') {
        await runProfileAudit(btn);
      }
    });
  });
}

// Run the LinkedIn profile auditor. The SW handles the message routing —
// it finds the LinkedIn tab, asks the content script to scrape, calls Gemini,
// returns the audit. We render the results inline below the banner.
async function runProfileAudit(btn) {
  const result = $('profile-audit-result');
  if (!result) return;
  btn.disabled = true;
  const original = btn.textContent;
  btn.textContent = '⏳ בודק (Gemini)...';
  result.style.display = '';
  result.innerHTML = '<div style="padding:14px; text-align:center; color:var(--muted, #888);">⏳ סורק את הפרופיל ומפעיל את Gemini... עד 15 שניות</div>';

  try {
    const r = await chrome.runtime.sendMessage({ type: 'AUDIT_LI_PROFILE' });
    if (!r?.ok) {
      result.innerHTML = `<div style="padding:14px; background:rgba(239,68,68,0.08); border:1px solid rgba(239,68,68,0.3); border-radius:8px; color:#fca5a5;">❌ ${r?.error || 'נכשל'}</div>`;
      return;
    }
    const { audit, profile } = r;
    const colors = { high: '#ef4444', medium: '#f59e0b', low: '#94a3b8' };
    const labels = { high: 'חשוב', medium: 'בינוני', low: 'משני' };
    const sectionLabels = { headline: 'כותרת', about: 'אודות', experience: 'ניסיון', featured: 'מודגש', banner: 'באנר', other: 'אחר' };

    result.innerHTML = `
      <div style="padding:16px; background:rgba(16,185,129,0.05); border:1px solid rgba(16,185,129,0.25); border-radius:10px;">
        <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:10px;">
          <div>
            <div style="font-size:13px; font-weight:600;">🔍 אודיט פרופיל</div>
            <div style="font-size:11px; color:var(--muted, #888);">${escapeHtml(profile.name || '')}</div>
          </div>
          <div style="text-align:center;">
            <div style="font-size:24px; font-weight:700; color:${audit.score >= 7 ? '#10b981' : audit.score >= 4 ? '#f59e0b' : '#ef4444'};">${audit.score}/10</div>
            <div style="font-size:10px; color:var(--muted, #888);">ציון כולל</div>
          </div>
        </div>
        <p style="font-size:12px; line-height:1.5; color:var(--text, #ddd); margin:6px 0 14px;">${escapeHtml(audit.summary)}</p>
        <div style="display:flex; flex-direction:column; gap:10px;">
          ${audit.items.map((it, i) => `
            <div style="padding:10px 12px; background:rgba(255,255,255,0.03); border:1px solid rgba(255,255,255,0.08); border-inline-start:3px solid ${colors[it.priority] || '#888'}; border-radius:6px;">
              <div style="display:flex; align-items:center; gap:6px; margin-bottom:4px;">
                <span style="font-size:10px; padding:1px 6px; border-radius:3px; background:${colors[it.priority]}22; color:${colors[it.priority]}; font-weight:600;">${labels[it.priority] || it.priority}</span>
                <span style="font-size:10px; padding:1px 6px; border-radius:3px; background:rgba(255,255,255,0.05); color:var(--muted, #888);">${sectionLabels[it.section] || it.section}</span>
              </div>
              <div style="font-size:12px; font-weight:600; color:var(--text, #ddd); margin-bottom:3px;">${escapeHtml(it.issue)}</div>
              <div style="font-size:11px; line-height:1.5; color:var(--muted, #aaa);">→ ${escapeHtml(it.action)}</div>
            </div>
          `).join('')}
        </div>
      </div>`;
  } catch (e) {
    result.innerHTML = `<div style="padding:14px; background:rgba(239,68,68,0.08); border:1px solid rgba(239,68,68,0.3); border-radius:8px; color:#fca5a5;">❌ ${escapeHtml(e?.message || String(e))}</div>`;
  } finally {
    btn.disabled = false;
    btn.textContent = original;
  }
}

// (escapeHtml is defined below for legacy reasons — leaving this comment as anchor)

// ===== Immediate sync — debounced =====
// Any user action that mutates data calls syncSoon(). After 400ms of quiet,
// we push everything to the server. Failures show a red toast so the user knows.

let _syncTimer = null;
let _syncInFlight = false;
function syncSoon(delayMs = 400) {
  clearTimeout(_syncTimer);
  _syncTimer = setTimeout(doSyncNow, delayMs);
}

async function doSyncNow() {
  if (_syncInFlight) { syncSoon(800); return; }
  _syncInFlight = true;
  setSyncPillSyncing();
  try {
    const r = await chrome.runtime.sendMessage({ type: 'SYNC_NOW' });
    if (!r?.ok) {
      toast(`שגיאת סנכרון: ${r?.error || 'לא ידוע'}`, 'err', 5000);
      setSyncPillError(r?.error);
    } else if (r.result?.skipped) {
      // Not logged in or similar — silent.
    } else {
      refreshSyncPill();
    }
  } catch (e) {
    toast(`שגיאת סנכרון: ${e.message}`, 'err', 5000);
  } finally {
    _syncInFlight = false;
  }
}

function setSyncPillSyncing() {
  const pill = $('sync-pill');
  pill.textContent = '🔄 מסנכרן...';
  pill.className = 'pill warn';
}
function setSyncPillError(msg) {
  const pill = $('sync-pill');
  pill.textContent = '❌ שגיאת סנכרון';
  pill.className = 'pill err';
  pill.title = msg || 'לחץ "סנכרן עכשיו" בהגדרות';
}

// ===== Button busy-state helper =====
// Wraps an async handler so the button shows a spinner + is disabled while running.
function wireBusy(btn, label, fn) {
  const original = btn.textContent;
  btn.addEventListener('click', async (...args) => {
    if (btn.disabled) return;
    btn.disabled = true;
    btn.classList.add('busy');
    btn.textContent = label || original;
    try { await fn(...args); }
    finally {
      btn.disabled = false;
      btn.classList.remove('busy');
      btn.textContent = original;
    }
  });
}

// ===== Auth gate (runs FIRST, before anything else) =====

async function bootstrap() {
  const session = await getSession();
  if (!session.token) {
    showLoginScreen();
    return;
  }
  // Optimistic: we have a stored token, so show the app immediately (no flicker,
  // works offline). Then verify in the background and ONLY bounce to the login
  // screen if the server DEFINITIVELY rejects the token (e.g. password reset /
  // logout-all). Network errors or slow responses never log the user out.
  enterApp(session.username, false);
  try {
    const v = await verifySession();
    if (!v.ok && !v.networkError) {
      showLoginScreen();
    } else if (v.ok) {
      IS_ADMIN = !!v.isAdmin;
      const adminBtn = $('admin-tab-btn');
      if (adminBtn) adminBtn.hidden = !v.isAdmin;
      $('user-chip').textContent = `👤 ${v.username || session.username}${v.isAdmin ? ' 🛡' : ''}`;
    }
  } catch { /* keep the user in — never log out on an unexpected error */ }
}

let IS_ADMIN = false;

function showLoginScreen() {
  $('login-screen').hidden = false;
  $('app').hidden = true;
  // Always start at the credentials step (a prior attempt may have left the OTP
  // step showing).
  if ($('login-step-otp')) { $('login-step-otp').hidden = true; $('login-step-creds').hidden = false; }
  _pendingLoginId = null; _pendingLoginPw = null;
  // Pre-fill the last known username (survives reinstall via storage.sync) so
  // that in the rare case the session token expired, she only re-types a password.
  (async () => {
    try {
      const { username } = await getSession();
      const u = username || (await getSetting('session.username'));
      if (u && !$('login-username').value) {
        $('login-username').value = u;
        $('login-password').focus();
        return;
      }
    } catch {}
    $('login-username').focus();
  })();
}

let livePollTimer = null;
let swHealthLastOk = 0;

function enterApp(username, isAdmin = false) {
  IS_ADMIN = isAdmin;
  $('login-screen').hidden = true;
  $('app').hidden = false;
  $('user-chip').textContent = `👤 ${username}${isAdmin ? ' 🛡' : ''}`;
  const adminBtn = $('admin-tab-btn');
  if (adminBtn) adminBtn.hidden = !isAdmin;
  refreshDashboard();
  showCampaignsList();
  startLivePoll();
  // Context banner — detect active tab platform and surface quick actions
  renderContextBanner().catch(() => {});
  // Show which Facebook account is logged in (best-effort)
  renderFbIdentity().catch(() => {});
}

// Populate the "connected Facebook account" pill in the header.
async function renderFbIdentity() {
  const pill = $('fb-identity-pill');
  if (!pill) return;
  try {
    const id = await chrome.runtime.sendMessage({ type: 'GET_FB_IDENTITY' });
    if (id && id.loggedIn) {
      const label = id.name || `ID ${id.fbUserId}`;
      pill.textContent = `📘 ${label}`;
      pill.title = `חשבון פייסבוק מחובר בדפדפן: ${id.name || ''} (${id.fbUserId})`;
      pill.className = 'pill';
      pill.hidden = false;
    } else {
      pill.hidden = true;
    }
  } catch { pill.hidden = true; }
}

// Refresh the dashboard, sync pill, and active tab content every 5s so
// the user sees changes happening in real time.
// ALSO: ping the service worker to keep it alive + verify it's responsive.
function startLivePoll() {
  if (livePollTimer) clearInterval(livePollTimer);
  livePollTimer = setInterval(async () => {
    // Ping the SW. This keeps it alive AND tells us if it's dead.
    try {
      const pong = await Promise.race([
        chrome.runtime.sendMessage({ type: 'PING' }),
        new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 3000)),
      ]);
      if (pong?.ok) {
        swHealthLastOk = Date.now();
        $('sync-pill').classList.remove('err');
      }
    } catch {
      // SW didn't respond within 3s
      const ago = swHealthLastOk ? Math.floor((Date.now() - swHealthLastOk) / 1000) : null;
      $('sync-pill').textContent = ago ? `⚠ SW לא מגיב ${ago}s` : '⚠ SW לא מגיב';
      $('sync-pill').className = 'pill err';
    }

    await refreshDashboard();
    const activeTab = document.querySelector('.tab.active')?.dataset.tab;
    if (activeTab === 'queue') renderQueue();
    else if (activeTab === 'logs') renderLogs();
  }, 5000);
}

$('login-btn').addEventListener('click', doLogin);
$('login-password').addEventListener('keydown', (e) => { if (e.key === 'Enter') doLogin(); });
$('login-username').addEventListener('keydown', (e) => { if (e.key === 'Enter') $('login-password').focus(); });
$('otp-verify-btn').addEventListener('click', doVerifyOtp);
$('login-otp').addEventListener('keydown', (e) => { if (e.key === 'Enter') doVerifyOtp(); });
$('otp-back-btn').addEventListener('click', backToCreds);
$('otp-resend-btn').addEventListener('click', async () => {
  if (!_pendingLoginId || !_pendingLoginPw) return backToCreds();
  $('otp-resend-btn').disabled = true; $('otp-resend-btn').textContent = 'שולח...';
  await login(_pendingLoginId, _pendingLoginPw);
  $('otp-resend-btn').disabled = false; $('otp-resend-btn').textContent = 'שלח קוד מחדש';
  $('login-error').hidden = true;
});

// The identifier (email/username) the current 2FA attempt is for.
let _pendingLoginId = null;
let _pendingLoginPw = null;

async function doLogin() {
  const username = $('login-username').value.trim();
  const password = $('login-password').value;
  $('login-error').hidden = true;
  if (!username || !password) {
    $('login-error').textContent = 'יש למלא אימייל/שם משתמש וסיסמה';
    $('login-error').hidden = false;
    return;
  }
  $('login-btn').disabled = true;
  $('login-btn').textContent = 'מתחבר...';
  const res = await login(username, password);
  $('login-btn').disabled = false;
  $('login-btn').textContent = 'היכנס';
  if (!res.ok) {
    $('login-error').textContent = res.error === 'invalid credentials' ? 'אימייל/שם משתמש או סיסמה שגויים' : ('שגיאה: ' + res.error);
    $('login-error').hidden = false;
    return;
  }
  // 2FA: password OK, a code was emailed. Switch to the code step.
  if (res.otpRequired) {
    _pendingLoginId = res.identifier || username;
    _pendingLoginPw = password;
    $('otp-sent-to').textContent = res.email
      ? `שלחנו קוד בן 6 ספרות ל-${res.email}`
      : 'שלחנו קוד בן 6 ספרות לאימייל שלך';
    $('login-step-creds').hidden = true;
    $('login-step-otp').hidden = false;
    $('login-otp').value = '';
    $('login-otp').focus();
    return;
  }
  enterApp(res.username); // no-email edge case: server issued a token directly
}

async function doVerifyOtp() {
  const code = $('login-otp').value.trim();
  $('login-error').hidden = true;
  if (!/^\d{6}$/.test(code)) {
    $('login-error').textContent = 'הזן קוד בן 6 ספרות';
    $('login-error').hidden = false;
    return;
  }
  $('otp-verify-btn').disabled = true;
  $('otp-verify-btn').textContent = 'מאמת...';
  const res = await verifyOtp(_pendingLoginId, code);
  $('otp-verify-btn').disabled = false;
  $('otp-verify-btn').textContent = 'אמת והיכנס';
  if (!res.ok) {
    $('login-error').textContent = res.error || 'קוד שגוי';
    $('login-error').hidden = false;
    return;
  }
  _pendingLoginPw = null;
  enterApp(res.username);
}

function backToCreds() {
  $('login-step-otp').hidden = true;
  $('login-step-creds').hidden = false;
  $('login-error').hidden = true;
  _pendingLoginId = null; _pendingLoginPw = null;
}

async function doLogout() {
  if (!confirm('להתנתק?')) return;
  await logout();
  showLoginScreen();
}

// ===== Tabs =====

document.querySelectorAll('.tab').forEach((btn) => {
  btn.addEventListener('click', () => switchTab(btn.dataset.tab));
});

function switchTab(name) {
  document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === name));
  document.querySelectorAll('.tab-panel').forEach((p) => p.classList.toggle('active', p.id === `tab-${name}`));
  if (name === 'campaigns') showCampaignsList();
  if (name === 'groups') renderGroups();
  if (name === 'queue') renderQueue();
  if (name === 'logs') renderLogs();
  if (name === 'settings') loadSettings();
  if (name === 'insights') loadInsights();
  if (name === 'admin') loadAdminPanel();
  if (name === 'ai') renderAiTools();
  if (name === 'leads') wireAiTools();
}

// ===== AI Tools tab (image gen · memory · cost · Hunter quick) =====
async function aiApi(path, opts = {}) {
  const { token } = await getSession();
  const { SYNC } = await import('../lib/config.js');
  const r = await fetch(SYNC.endpoint + path, {
    ...opts,
    headers: { 'X-Session-Token': token, 'Content-Type': 'application/json', ...(opts.headers || {}) },
  });
  return r.json().catch(() => ({ ok: false }));
}

let aiToolsWired = false;
function wireAiTools() {
  if (aiToolsWired) return; aiToolsWired = true;

  $('ai-img-gen-btn')?.addEventListener('click', async () => {
    const prompt = $('ai-img-prompt').value.trim();
    if (!prompt) return;
    const status = $('ai-img-status'), out = $('ai-img-result');
    status.textContent = '⏳ יוצר תמונה... (10-30 שניות)'; out.innerHTML = '';
    try {
      const r = await aiApi('/api/v1/ai/generate', { method: 'POST',
        body: JSON.stringify({ prompt, kind: 'image', feature: 'popup_image' }) });
      if (r.ok && r.dataUrl) {
        status.textContent = `✓ ${r.provider || ''}${r.isTrial ? ' (trial)' : ''}`;
        out.innerHTML = `<img src="${r.dataUrl}" style="max-width:100%;border-radius:8px;display:block;">
          <a class="btn" href="${r.dataUrl}" download="organicai.png" style="margin-top:6px;display:inline-block;">⬇ הורד</a>`;
      } else status.textContent = '✗ ' + (r.error || 'נכשל');
    } catch (e) { status.textContent = '✗ ' + String(e?.message || e); }
  });

  $('ai-mem-add-btn')?.addEventListener('click', async () => {
    const content = $('ai-mem-content').value.trim();
    if (!content) return;
    await aiApi('/api/v1/mcp/call', { method: 'POST',
      body: JSON.stringify({ tool: 'ai.memory.add', args: { kind: $('ai-mem-kind').value, content, weight: 5 } }) });
    $('ai-mem-content').value = '';
    loadAiMemory();
  });

  // ── Leads tab quick-add ──
  $('leads-add-btn')?.addEventListener('click', async () => {
    const url = $('leads-url-input').value.trim();
    if (!url) return;
    const st = $('leads-add-status'); st.textContent = '⏳ מוסיף...';
    const r = await aiApi('/api/v1/hunter/prospects/add', { method: 'POST', body: JSON.stringify({ url }) });
    st.textContent = r.ok ? '✓ נוסף ליד — המשך בדשבורד' : (r.duplicate ? 'כבר קיים' : '✗ ' + (r.error || 'נכשל'));
    $('leads-url-input').value = '';
  });
  $('leads-open-dashboard-btn')?.addEventListener('click', () => {
    chrome.tabs.create({ url: 'https://app.organicai.doogree.co.il/#hunter' });
  });

  $('ai-hunter-add-btn')?.addEventListener('click', async () => {
    const url = $('ai-hunter-url').value.trim();
    if (!url) return;
    const st = $('ai-hunter-status'); st.textContent = '⏳ מוסיף...';
    const r = await aiApi('/api/v1/hunter/prospects/add', { method: 'POST', body: JSON.stringify({ url }) });
    st.textContent = r.ok ? '✓ נוסף ליד — המשך בדשבורד' : (r.duplicate ? 'כבר קיים' : '✗ ' + (r.error || 'נכשל'));
    $('ai-hunter-url').value = '';
  });

  $('ai-hunter-open-btn')?.addEventListener('click', () => {
    chrome.tabs.create({ url: 'https://app.organicai.doogree.co.il/#hunter' });
  });

  $('ai-hunter-gsearch-btn')?.addEventListener('click', async () => {
    const query = $('ai-hunter-gquery').value.trim();
    if (!query) return;
    const st = $('ai-hunter-gsearch-status');
    st.textContent = '⏳ מחפש בגוגל ברקע... (10-20 שניות)';
    try {
      const r = await chrome.runtime.sendMessage({ type: 'GOOGLE_DISCOVER', payload: { query } });
      st.textContent = r?.ok
        ? `✓ נוספו ${r.added} עסקים (${r.organic} אורגני · ${r.local} מקומי) — המשך ב-Hunter בדשבורד`
        : '✗ ' + (r?.error || 'נכשל');
    } catch (e) { st.textContent = '✗ ' + String(e?.message || e); }
  });
}

async function loadAiMemory() {
  try {
    const r = await aiApi('/api/v1/mcp/call', { method: 'POST', body: JSON.stringify({ tool: 'ai.memory.list', args: {} }) });
    const mems = r?.result?.memories || [];
    $('ai-mem-list').innerHTML = mems.length
      ? mems.slice(0, 8).map(m => `<div class="row" style="font-size:12px;gap:6px;align-items:center;"><span class="pill muted">${escapeHtml(m.kind)}</span><span style="flex:1;">${escapeHtml((m.content || '').slice(0, 80))}</span><span class="muted">w${m.weight}</span></div>`).join('')
      : '<span class="muted" style="font-size:12px;">עדיין אין זיכרונות</span>';
  } catch {}
}

// ── Live agent activity feed ("not in the dark") ──
// Every background automation step already calls Logs.add, which now also pushes
// an AGENT_ACTIVITY message. This renders the recent feed and updates it live.
function activityIcon(level) {
  return level === 'error' ? '🔴' : level === 'warn' ? '🟡' : '🟢';
}
function activityRow(e) {
  const t = new Date(e.at || e.createdAt || Date.now());
  const hh = String(t.getHours()).padStart(2, '0'), mm = String(t.getMinutes()).padStart(2, '0');
  return `<div class="row" style="gap:6px;align-items:flex-start;padding:3px 0;border-bottom:1px solid rgba(0,0,0,0.05);">
    <span>${activityIcon(e.level)}</span>
    <span style="flex:1;line-height:1.4;">${escapeHtml(e.message || '')}</span>
    <span class="muted" style="font-size:10px;white-space:nowrap;">${hh}:${mm}</span>
  </div>`;
}
async function renderAgentActivity() {
  const feed = $('agent-activity-feed');
  if (!feed) return;
  try {
    const rows = await Logs.list(25);
    $('agent-activity-count') && ($('agent-activity-count').textContent = rows.length ? `${rows.length} פעולות אחרונות` : '');
    feed.innerHTML = rows.length
      ? rows.map(activityRow).join('')
      : '<span class="muted">עדיין אין פעילות. כשהסוכן יפעל (פרסום, Hunter, סריקה) — זה יופיע כאן חי.</span>';
  } catch {
    feed.innerHTML = '<span class="muted">לא ניתן לטעון פעילות.</span>';
  }
}
function prependActivity(entry) {
  const feed = $('agent-activity-feed');
  if (!feed) return;
  const first = feed.querySelector('.muted');
  if (first && feed.children.length === 1) feed.innerHTML = '';
  feed.insertAdjacentHTML('afterbegin', activityRow(entry));
  while (feed.children.length > 40) feed.lastElementChild?.remove();
}

// 🎥 Flight-recorder toggle. `debugger` is an OPTIONAL permission (keeping it
// optional means an auto-update never disables the extension pending
// re-approval) and chrome.permissions.request() needs a user gesture — hence a
// button here rather than an automatic grab in the service worker.
async function refreshRecStatus() {
  const st = $('rec-status'), btn = $('rec-enable-btn');
  if (!st || !btn) return;
  let granted = false;
  try { granted = await chrome.permissions.contains({ permissions: ['debugger'] }); } catch {}
  if (granted) {
    st.textContent = '🟢 מקליט — צילומים + טקסט';
    btn.textContent = '🎥 מוקלט'; btn.disabled = true;
  } else {
    st.textContent = '🟡 טקסט ותוצאה בלבד (ללא צילומים)';
    btn.textContent = '🎥 הפעל הקלטת מסך'; btn.disabled = false;
  }
}
let recToggleWired = false;
async function wireRecToggle() {
  if (recToggleWired) return; recToggleWired = true; // renderAiTools re-runs on every tab open
  $('rec-enable-btn')?.addEventListener('click', async () => {
    try {
      const ok = await chrome.permissions.request({ permissions: ['debugger'] });
      if (ok) {
        await setSetting('agentRecording', true);
        toast('🎥 הקלטת מסך הופעלה — הסוכן יצלם את עבודתו', 'ok', 5000);
      } else {
        toast('ההרשאה לא ניתנה — נמשיך להקליט טקסט ותוצאה בלבד', 'info', 5000);
      }
    } catch (e) { toast('❌ ' + String(e?.message || e), 'err', 5000); }
    refreshRecStatus();
  });
}

async function renderAiTools() {
  wireAiTools();
  wireRecToggle();
  refreshRecStatus();
  loadAiMemory();
  renderAgentActivity();
  try {
    const c = await aiApi('/api/v1/ai/cost?range=month');
    if (c.ok) {
      $('ai-cost-summary').textContent = `30 ימים: ~$${Number(c.totalCostUsd || 0).toFixed(3)} · ${c.totalCalls || 0} קריאות`;
      const bp = c.byProvider || {};
      const keys = Object.keys(bp);
      $('ai-cost-detail').innerHTML = keys.length
        ? keys.map(k => `<div class="row" style="font-size:12px;justify-content:space-between;"><span>${escapeHtml(k)}</span><span class="muted">$${Number(bp[k] || 0).toFixed(3)}</span></div>`).join('')
        : '<span class="muted" style="font-size:12px;">אין נתונים עדיין</span>';
    }
  } catch {}
  try {
    const ch = await aiApi('/api/v1/hunter/channels');
    if (ch.ok && ch.channels) {
      const s = ch.channels.sending || {};
      const ready = Object.keys(s).filter(k => s[k]).length;
      $('ai-hunter-summary').textContent = ch.channels.can_message ? `${ready} ערוצים פעילים` : 'מילוי טפסים בלבד';
    }
  } catch {}
}

// ===== Insights =====

async function loadInsights() {
  const sel = $('insight-campaign-select');
  const campaigns = await Campaigns.list();
  sel.innerHTML = campaigns.length
    ? campaigns.map((c) => `<option value="${c.id}">${escapeHtml(c.name)}</option>`).join('')
    : '<option value="">אין קמפיינים</option>';
  if (!sel.onchange) sel.addEventListener('change', renderInsightForCampaign);
  if (campaigns.length) renderInsightForCampaign();
  renderTodayPosts();
}

// ===== Published posts — filtered view =====

['today-refresh-btn', 'today-date-filter', 'today-platform-filter', 'today-type-filter',
 'today-sort', 'today-min-views', 'today-from', 'today-to'].forEach((id) => {
  const el = $(id);
  if (el) el.addEventListener('change', renderTodayPosts);
});
$('today-refresh-btn').addEventListener('click', renderTodayPosts);
$('today-date-filter').addEventListener('change', () => {
  $('today-custom-range').hidden = $('today-date-filter').value !== 'custom';
});

let metricsCache = new Map(); // jobId → latest metrics from /metrics/job

async function loadMetricsForJobs(jobIds) {
  // Bulk-fetch latest metrics for visible jobs from D1
  try {
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    if (!token) return;
    // We have /metrics/job/:id — fetch each. For perf, cache aggressively.
    for (const jobId of jobIds) {
      if (metricsCache.has(jobId)) continue;
      const res = await fetch(`${SYNC.endpoint}/metrics/job/${jobId}`, {
        headers: { 'X-Session-Token': token },
      });
      const json = await res.json();
      if (json.ok && json.snapshots?.length) {
        // Latest snapshot is last
        metricsCache.set(jobId, json.snapshots[json.snapshots.length - 1]);
      } else {
        metricsCache.set(jobId, null);
      }
    }
  } catch {}
}

function getDateRange() {
  const filter = $('today-date-filter').value;
  const now = Date.now();
  const midnight = new Date(new Date().setHours(0, 0, 0, 0)).getTime();
  if (filter === 'today') return { from: midnight, to: now };
  if (filter === 'yesterday') return { from: midnight - 86400000, to: midnight };
  if (filter === '7d') return { from: now - 7 * 86400000, to: now };
  if (filter === '30d') return { from: now - 30 * 86400000, to: now };
  if (filter === 'all') return { from: 0, to: now };
  if (filter === 'custom') {
    const fromV = $('today-from').value;
    const toV = $('today-to').value;
    return {
      from: fromV ? new Date(fromV).getTime() : 0,
      to: toV ? new Date(toV).getTime() + 86400000 : now,
    };
  }
  return { from: midnight, to: now };
}

async function renderTodayPosts() {
  const list = $('today-posts-list');
  const platformFilter = $('today-platform-filter').value;
  const typeFilter = $('today-type-filter').value;
  const sortBy = $('today-sort').value;
  const minViews = Number($('today-min-views').value) || 0;
  const { from, to } = getDateRange();

  const allJobs = await Jobs.list();
  const groups = await Groups.list();
  const groupById = new Map(groups.map((g) => [g.id, g]));

  // Base filter — done jobs in date range
  let filtered = allJobs.filter((j) =>
    j.status === 'done' && (j.completedAt || 0) >= from && (j.completedAt || 0) <= to
  );

  // Platform filter
  if (platformFilter) {
    filtered = filtered.filter((j) => groupById.get(j.groupId)?.platform === platformFilter);
  }

  // Type filter — needs post lookup
  if (typeFilter) {
    const posts = await Posts.list();
    const postById = new Map(posts.map((p) => [p.id, p]));
    filtered = filtered.filter((j) => {
      const p = postById.get(j.chosenPostId);
      return p?.postType === typeFilter;
    });
  }

  // Fetch metrics for visible jobs (bulk)
  await loadMetricsForJobs(filtered.map((j) => j.id));

  // Min views filter
  if (minViews > 0) {
    filtered = filtered.filter((j) => {
      const m = metricsCache.get(j.id);
      return (m?.views || 0) >= minViews;
    });
  }

  // Sort
  const sorters = {
    newest: (a, b) => (b.completedAt || 0) - (a.completedAt || 0),
    oldest: (a, b) => (a.completedAt || 0) - (b.completedAt || 0),
    views: (a, b) => (metricsCache.get(b.id)?.views || 0) - (metricsCache.get(a.id)?.views || 0),
    reactions: (a, b) => (metricsCache.get(b.id)?.reactions || 0) - (metricsCache.get(a.id)?.reactions || 0),
    comments: (a, b) => (metricsCache.get(b.id)?.comments || 0) - (metricsCache.get(a.id)?.comments || 0),
    engagement: (a, b) => {
      const ea = metricsCache.get(a.id) || {};
      const eb = metricsCache.get(b.id) || {};
      const sa = (ea.reactions || 0) + (ea.comments || 0) * 2 + (ea.shares || 0) * 3;
      const sb = (eb.reactions || 0) + (eb.comments || 0) * 2 + (eb.shares || 0) * 3;
      return sb - sa;
    },
  };
  filtered.sort(sorters[sortBy] || sorters.newest);

  $('today-posts-count').textContent = `(${filtered.length})`;
  list.innerHTML = '';

  if (!filtered.length) {
    list.appendChild(emptyState('📆', 'אין פוסטים בטווח שבחרת', 'נסה לשנות פילטרים'));
    return;
  }

  const platformIcons = {
    facebook: '📘', linkedin: '💼', twitter: '𝕏', reddit: '🟠', instagram: '📷',
  };
  const typeIcons = {
    text: '📝', colored: '🎨', link: '🔗', poll: '📊', gif: '🎉', feeling: '😊',
    'marketplace-item': '🛒', 'marketplace-vehicle': '🚗',
    'marketplace-property-sale': '🏠', 'marketplace-property-rent': '🔑',
    profile: '👤', page: '📄', story: '📸', reel: '🎬', event: '📅', share: '🔁', album: '🖼',
  };

  for (const job of filtered) {
    const group = groupById.get(job.groupId);
    const post = job.chosenPostId ? await Posts.get(job.chosenPostId) : null;
    const campaign = job.campaignId ? await Campaigns.get(job.campaignId) : null;
    const platform = group?.platform || 'facebook';
    const metrics = metricsCache.get(job.id);

    const dateObj = new Date(job.completedAt);
    const dateStr = dateObj.toLocaleDateString('he-IL', { day: '2-digit', month: '2-digit' });
    const timeStr = dateObj.toLocaleTimeString('he-IL', { hour: '2-digit', minute: '2-digit' });
    const minAgo = Math.round((Date.now() - job.completedAt) / 60000);
    const agoText = minAgo < 60 ? `לפני ${minAgo} דק'` :
                    minAgo < 1440 ? `לפני ${Math.round(minAgo / 60)} שעות` :
                    `לפני ${Math.round(minAgo / 1440)} ימים`;

    const li = document.createElement('li');
    li.innerHTML = `
      <div class="row-main">
        <span style="font-size:18px;" title="${platform}">${platformIcons[platform] || '📡'}</span>
        <span style="font-size:14px;" title="${post?.postType || 'text'}">${typeIcons[post?.postType] || '📝'}</span>
        <span class="name">${escapeHtml(group?.name || job.groupId)}</span>
        <span class="muted">${dateStr} ${timeStr} · ${agoText}</span>
      </div>
      ${post ? `<div class="row-preview" title="לחץ להרחבה">${escapeHtml(post.text || post.title || '')}</div>` : ''}
      ${metrics ? `
        <div class="row-meta">
          ${metrics.views ? `<span>👁 ${fmtCount(metrics.views)}</span>` : ''}
          <span>❤ ${metrics.reactions || 0}</span>
          <span>💬 ${metrics.comments || 0}</span>
          <span>🔁 ${metrics.shares || 0}</span>
        </div>
      ` : '<div class="row-meta muted">אין מטריקות עדיין</div>'}
      <div class="row-meta">
        ${post?.title ? `<span>📝 ${escapeHtml(post.title)}</span>` : ''}
        ${campaign?.name ? `<span>📁 ${escapeHtml(campaign.name)}</span>` : ''}
        <div class="row-actions"></div>
      </div>
    `;
    const preview = li.querySelector('.row-preview');
    if (preview) preview.addEventListener('click', (e) => e.currentTarget.classList.toggle('expanded'));

    const actions = li.querySelector('.row-actions');
    if (job.postUrl) {
      const openBtn = mkBtn('🔗', () => chrome.tabs.create({ url: job.postUrl, active: true }));
      openBtn.title = 'פתח את הפוסט: ' + job.postUrl;
      actions.appendChild(openBtn);
    }
    // Force refresh metrics for this single job
    const refreshBtn = mkBtn('📊', async () => {
      metricsCache.delete(job.id);
      await chrome.runtime.sendMessage({ type: 'FORCE_REFRESH_METRICS', payload: { jobId: job.id } });
      toast('בוקש רענון. בעוד ~דקה התוצאה תופיע.', 'ok', 3000);
    });
    refreshBtn.title = 'רענן מטריקות מהפלטפורמה';
    actions.appendChild(refreshBtn);

    list.appendChild(li);
  }
}

// Force refresh all visible metrics
$('refresh-all-metrics-btn').addEventListener('click', async () => {
  const items = $('today-posts-list').querySelectorAll('li');
  if (!items.length) return;
  metricsCache.clear();
  const allJobs = await Jobs.list();
  // Schedule force-refresh for all done jobs currently displayed
  const { from, to } = getDateRange();
  const dueJobs = allJobs.filter((j) =>
    j.status === 'done' && j.postUrl && (j.completedAt || 0) >= from && (j.completedAt || 0) <= to
  );
  for (const j of dueJobs) {
    await Jobs.update(j, { trackingDueAt: Date.now() });
  }
  toast(`רענון תוזמן ל-${dueJobs.length} פוסטים. ירוץ ברקע.`, 'ok', 4000);
  syncSoon();
});

// CSV export of visible filter
$('export-today-csv-btn').addEventListener('click', async () => {
  const allJobs = await Jobs.list();
  const groups = await Groups.list();
  const posts = await Posts.list();
  const campaigns = await Campaigns.list();
  const groupById = new Map(groups.map((g) => [g.id, g]));
  const postById = new Map(posts.map((p) => [p.id, p]));
  const campById = new Map(campaigns.map((c) => [c.id, c]));

  const platformFilter = $('today-platform-filter').value;
  const typeFilter = $('today-type-filter').value;
  const { from, to } = getDateRange();
  let filtered = allJobs.filter((j) =>
    j.status === 'done' && (j.completedAt || 0) >= from && (j.completedAt || 0) <= to
  );
  if (platformFilter) filtered = filtered.filter((j) => groupById.get(j.groupId)?.platform === platformFilter);
  if (typeFilter) filtered = filtered.filter((j) => postById.get(j.chosenPostId)?.postType === typeFilter);

  const rows = filtered.map((j) => {
    const g = groupById.get(j.groupId);
    const p = postById.get(j.chosenPostId);
    const c = campById.get(j.campaignId);
    const m = metricsCache.get(j.id) || {};
    return {
      datetime: new Date(j.completedAt).toISOString(),
      platform: g?.platform || '',
      groupName: g?.name || '',
      campaignName: c?.name || '',
      postTitle: p?.title || '',
      postType: p?.postType || 'text',
      postText: (p?.text || '').slice(0, 500),
      postUrl: j.postUrl || '',
      views: m.views || '',
      reactions: m.reactions || 0,
      comments: m.comments || 0,
      shares: m.shares || 0,
    };
  });
  downloadCSV(`posts-filtered-${ts()}.csv`, toCSV(rows));
  toast(`יוצא ${rows.length} פוסטים`, 'ok');
});

async function renderInsightForCampaign() {
  const campaignId = $('insight-campaign-select').value;
  if (!campaignId) return;
  $('insight-overview').hidden = true;
  $('insight-posts').hidden = true;
  $('insight-groups').hidden = true;
  $('insight-top-posts').hidden = true;
  $('insight-group-detail').hidden = true;
  loadTopMetrics();

  try {
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    const res = await fetch(`${SYNC.endpoint}/insights/campaign/${campaignId}`, {
      headers: { 'X-Session-Token': token },
    });
    const json = await res.json();
    if (!json.ok) { toast(json.error || 'נכשל', 'err'); return; }

    const { campaign, stats, posts, groups } = json;

    // Overview
    $('insight-overview').hidden = false;
    const successRate = stats.total > 0 ? Math.round((stats.done / stats.total) * 100) : 0;
    $('insight-overview-content').innerHTML = `
      <div class="dashboard" style="margin:0;">
        <div class="stat"><b>${stats.done || 0}</b><span>הצלחות</span></div>
        <div class="stat"><b>${stats.failed || 0}</b><span>כשלונות</span></div>
        <div class="stat"><b>${stats.queued || 0}</b><span>בתור</span></div>
        <div class="stat"><b>${successRate}%</b><span>אחוז הצלחה</span></div>
      </div>
    `;
    $('insight-overview').dataset.campaignName = campaign.name;
    $('insight-overview').dataset.stats = JSON.stringify(stats);

    // Posts
    $('insight-posts').hidden = false;
    const postsList = $('insight-posts-list');
    postsList.innerHTML = '';
    if (!posts.length) {
      postsList.appendChild(emptyState('📝', 'אין פוסטים', ''));
    } else {
      for (const p of posts) {
        const sr = p.attempts > 0 ? Math.round((p.successes / p.attempts) * 100) : 0;
        const icon = { text: '📝', colored: '🎨', link: '🔗' }[p.post_type || 'text'];
        const li = document.createElement('li');
        li.innerHTML = `
          <span>${icon}</span>
          <span class="name">${escapeHtml(p.title)}</span>
          <span class="muted">${p.successes}/${p.attempts} (${sr}%)</span>
        `;
        postsList.appendChild(li);
      }
    }

    // Groups
    $('insight-groups').hidden = false;
    const groupsList = $('insight-groups-list');
    groupsList.innerHTML = '';
    if (!groups.length) {
      groupsList.appendChild(emptyState('👥', 'עוד לא פירסם', ''));
    } else {
      for (const g of groups) {
        const sr = g.attempts > 0 ? Math.round((g.successes / g.attempts) * 100) : 0;
        const li = document.createElement('li');
        li.innerHTML = `
          <span class="name">${escapeHtml(g.name)}</span>
          <span class="muted">${g.successes}/${g.attempts} (${sr}%)</span>
          <span class="muted">${g.last_at ? fmtTime(g.last_at) : '—'}</span>
        `;
        if (g.post_policy === 'instant') li.appendChild(makeBadge('🚀', '', 'done'));
        else if (g.post_policy === 'approval') li.appendChild(makeBadge('⏳', '', 'queued'));
        li.appendChild(mkBtn('📜', () => showGroupDetail(g.id, g.name)));
        groupsList.appendChild(li);
      }
    }
  } catch (e) {
    toast(String(e), 'err', 5000);
  }
}

async function showGroupDetail(groupId, groupName) {
  $('insight-overview').hidden = true;
  $('insight-posts').hidden = true;
  $('insight-groups').hidden = true;
  $('insight-group-detail').hidden = false;
  $('insight-group-detail-name').textContent = groupName;
  $('insight-group-detail-stats').textContent = 'טוען...';
  $('insight-group-detail-history').innerHTML = '';

  try {
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    const res = await fetch(`${SYNC.endpoint}/insights/group/${groupId}`, {
      headers: { 'X-Session-Token': token },
    });
    const json = await res.json();
    if (!json.ok) { toast(json.error || 'נכשל', 'err'); return; }
    const { stats, history } = json;
    $('insight-group-detail-stats').textContent =
      `${stats.done || 0}✅ · ${stats.failed || 0}❌ · אחרון: ${stats.last_success_at ? fmtTime(stats.last_success_at) : 'אף פעם'}`;
    const list = $('insight-group-detail-history');
    if (!history.length) {
      list.appendChild(emptyState('📭', 'אין היסטוריה', ''));
      return;
    }
    for (const h of history) {
      const li = document.createElement('li');
      const typeIcon = { text: '📝', colored: '🎨', link: '🔗' }[h.post_type || 'text'];
      const errTitle = h.last_error ? ` title="${escapeHtml(h.last_error)}"` : '';
      li.innerHTML = `
        <span>${typeIcon}</span>
        <span class="name"${errTitle}>${escapeHtml(h.post_title || '—')}</span>
        <span class="badge ${h.status}">${h.status}</span>
        <span class="muted">${fmtTime(h.completed_at || h.scheduled_at)}</span>
      `;
      list.appendChild(li);
    }
  } catch (e) {
    toast(String(e), 'err', 5000);
  }
}

async function loadTopMetrics() {
  try {
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    const res = await fetch(`${SYNC.endpoint}/metrics/top?limit=10`, {
      headers: { 'X-Session-Token': token },
    });
    const json = await res.json();
    if (!json.ok || !json.top?.length) return;

    $('insight-top-posts').hidden = false;
    const list = $('insight-top-list');
    list.innerHTML = '';
    for (const m of json.top) {
      const li = document.createElement('li');
      li.innerHTML = `
        <div class="row-main">
          <span class="name">${escapeHtml(m.post_title || '—')}</span>
          <span class="badge done">⚡ ${m.engagement_score}</span>
        </div>
        <div class="row-meta">
          <span>👥 ${escapeHtml(m.group_name || '—')}</span>
          <span>❤ ${m.reactions || 0}</span>
          <span>💬 ${m.comments || 0}</span>
          <span>🔁 ${m.shares || 0}</span>
          <span>🕒 ${m.hours_since_publish ? `${Math.round(m.hours_since_publish)}h` : '—'}</span>
          ${m.post_url ? `<a href="${escapeHtml(m.post_url)}" target="_blank" style="text-decoration:none;">🔗</a>` : ''}
        </div>
      `;
      list.appendChild(li);
    }
  } catch (e) {
    console.warn('top metrics failed', e);
  }
}

$('insight-back-btn').addEventListener('click', renderInsightForCampaign);

// 🤖 Gemini analysis of the entire campaign
$('insight-gemini-btn').addEventListener('click', async () => {
  const btn = $('insight-gemini-btn');
  const out = $('insight-gemini-output');
  btn.disabled = true; btn.classList.add('busy');
  out.hidden = false;
  out.textContent = '⏳ שולח ל-Gemini לניתוח...';
  try {
    const { geminiText } = await import('../lib/gemini.js');
    const campaignId = $('insight-campaign-select').value;
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    const res = await fetch(`${SYNC.endpoint}/insights/campaign/${campaignId}`, {
      headers: { 'X-Session-Token': token },
    });
    const data = await res.json();
    if (!data.ok) throw new Error(data.error);

    // Also fetch the posts text from local DB for richer analysis
    const localPosts = await Posts.listByCampaign(campaignId);
    const postsSummary = localPosts.map((p) =>
      `- "${p.title}" (${p.postType||'text'}): "${(p.text||'').slice(0,120)}..."`
    ).join('\n');

    const prompt = `אתה יועץ שיווק בקבוצות פייסבוק. ניתוח קמפיין:

קמפיין: ${data.campaign.name}
סטטיסטיקות: ${data.stats.done} הצלחות, ${data.stats.failed} כשלונות, אחוז הצלחה ${Math.round(data.stats.done/(data.stats.total||1)*100)}%

פוסטים:
${postsSummary}

ביצועי פוסטים: ${data.posts.map(p=>`"${p.title}" ${p.successes}/${p.attempts}`).join(', ')}
ביצועי קבוצות (top 5): ${data.groups.slice(0,5).map(g=>`${g.name}: ${g.successes}/${g.attempts}`).join('; ')}

אנא תן ניתוח קצר (עד 200 מילים) בעברית:
1. מה עובד טוב?
2. מה לא עובד?
3. 3 המלצות קונקרטיות לשיפור`;

    const r = await geminiText(prompt, { maxTokens: 600, temperature: 0.5 });
    if (!r.ok) {
      out.textContent = `❌ ${r.error}\n\n(וודא שהגדרת Gemini key בהגדרות)`;
      return;
    }
    out.textContent = r.text;
  } catch (e) {
    out.textContent = '❌ ' + String(e?.message || e);
  } finally {
    btn.disabled = false; btn.classList.remove('busy');
  }
});

// ===== Dashboard =====

async function refreshDashboard() {
  const campaigns = await Campaigns.list();
  const jobs = await Jobs.list();
  const groups = await Groups.list();
  const since = Date.now() - 24 * 3600 * 1000;
  $('stat-active').textContent = campaigns.filter((c) => c.status === 'active').length;
  $('stat-today').textContent = jobs.filter((j) => j.status === 'done' && (j.completedAt || 0) >= since).length;
  $('stat-queued').textContent = jobs.filter((j) => j.status === 'queued').length;
  $('stat-groups').textContent = groups.length;
  // Make "today" stat clickable → jump to insights tab
  const todayStat = $('stat-today').parentElement;
  if (!todayStat.dataset.clickable) {
    todayStat.style.cursor = 'pointer';
    todayStat.title = 'לחץ לראות את כל הפוסטים מהיום';
    todayStat.addEventListener('click', () => switchTab('insights'));
    todayStat.dataset.clickable = '1';
  }
  await refreshSyncPill();
}

async function refreshSyncPill() {
  const pill = $('sync-pill');
  const last = await getSetting('lastSyncAt');
  if (!last) { pill.textContent = '⏳ עוד לא סונכרן'; pill.className = 'pill warn'; return; }
  const min = Math.floor((Date.now() - last) / 60000);
  pill.textContent = `☁ סונכרן לפני ${min} דק'`;
  pill.className = 'pill ok';
}

// ========== CAMPAIGNS ==========

let currentCampaignId = null;
let editingPostId = null;

$('new-campaign-btn').addEventListener('click', async () => {
  const c = await Campaigns.create({ name: 'קמפיין חדש' });
  syncSoon();
  openCampaign(c.id);
});

$('back-to-campaigns-btn').addEventListener('click', showCampaignsList);

function showCampaignsList() {
  currentCampaignId = null;
  $('campaigns-list-view').hidden = false;
  $('campaign-detail-view').hidden = true;
  renderCampaignsList();
}

async function renderCampaignsList() {
  const list = $('campaigns-list');
  const campaigns = await Campaigns.list();
  list.innerHTML = '';
  if (!campaigns.length) {
    list.appendChild(emptyState('🎯', 'אין עדיין קמפיינים', 'לחץ "קמפיין חדש" כדי להתחיל'));
    return;
  }
  for (const c of campaigns) {
    const posts = await Posts.listByCampaign(c.id);
    const li = document.createElement('li');
    let scheduleHint = '';
    const now = Date.now();
    if (c.scheduleStartAt && c.scheduleStartAt > now && c.status !== 'active') {
      scheduleHint = ` · ⏰ מתחיל ${fmtTime(c.scheduleStartAt)}`;
    } else if (c.scheduleEndAt && c.scheduleEndAt > now && c.status === 'active') {
      scheduleHint = ` · 🛑 מסיים ${fmtTime(c.scheduleEndAt)}`;
    }
    li.innerHTML = `
      <span class="name">${escapeHtml(c.name)}</span>
      <span class="badge ${c.status}">${statusLabel(c.status)}</span>
      <span class="muted">${posts.length}📝 · ${(c.groupIds || []).length}👥${scheduleHint}</span>
    `;
    li.appendChild(mkBtn('פתח', () => openCampaign(c.id)));
    list.appendChild(li);
  }
}

async function openCampaign(id) {
  currentCampaignId = id;
  $('campaigns-list-view').hidden = true;
  $('campaign-detail-view').hidden = false;
  await renderCampaignDetail();
}

async function renderCampaignDetail() {
  const c = await Campaigns.get(currentCampaignId);
  if (!c) return showCampaignsList();
  $('campaign-detail-name').textContent = c.name;
  $('campaign-detail-status').textContent = statusLabel(c.status);
  $('campaign-detail-status').className = `badge ${c.status}`;
  $('campaign-name-input').value = c.name;
  $('campaign-rotation-select').value = c.rotation || 'lru';
  $('campaign-schedule-start').value = tsToLocalInput(c.scheduleStartAt);
  $('campaign-schedule-end').value = tsToLocalInput(c.scheduleEndAt);
  $('start-campaign-btn').hidden = c.status === 'active' || c.status === 'paused';
  $('pause-campaign-btn').hidden = c.status !== 'active';
  $('resume-campaign-btn').hidden = c.status !== 'paused';
  await renderCampaignPosts();
  await renderCampaignGroups();
}

// Convert unix ms ↔ "yyyy-MM-ddTHH:mm" expected by <input type="datetime-local">
function tsToLocalInput(ts) {
  if (!ts) return '';
  const d = new Date(ts);
  const pad = (n) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
function localInputToTs(s) {
  if (!s) return null;
  return new Date(s).getTime();
}

$('save-campaign-btn').addEventListener('click', async () => {
  const c = await Campaigns.get(currentCampaignId);
  await Campaigns.update(c, {
    name: $('campaign-name-input').value.trim() || 'ללא שם',
    rotation: $('campaign-rotation-select').value,
    scheduleStartAt: localInputToTs($('campaign-schedule-start').value),
    scheduleEndAt: localInputToTs($('campaign-schedule-end').value),
  });
  syncSoon();
  toast('נשמר', 'ok', 1200);
  await renderCampaignDetail();
  refreshDashboard();
});

$('start-campaign-btn').addEventListener('click', async () => {
  const c = await Campaigns.get(currentCampaignId);
  await Campaigns.update(c, {
    name: $('campaign-name-input').value.trim() || 'ללא שם',
    rotation: $('campaign-rotation-select').value,
  });
  const res = await chrome.runtime.sendMessage({ type: 'START_CAMPAIGN', payload: { campaignId: currentCampaignId } });
  if (res?.ok) {
    toast(`הקמפיין הופעל — ${res.count} משימות נוספו לתור`, 'ok');
    syncSoon();
    await renderCampaignDetail();
    refreshDashboard();
  } else {
    toast(res?.error || 'שגיאה לא ידועה', 'err', 5000);
  }
});

$('pause-campaign-btn').addEventListener('click', async () => {
  await chrome.runtime.sendMessage({ type: 'PAUSE_CAMPAIGN', payload: { campaignId: currentCampaignId } });
  toast('הושהה', 'ok', 1200);
  syncSoon();
  await renderCampaignDetail();
  refreshDashboard();
});

$('resume-campaign-btn').addEventListener('click', async () => {
  await chrome.runtime.sendMessage({ type: 'RESUME_CAMPAIGN', payload: { campaignId: currentCampaignId } });
  toast('ממשיך', 'ok', 1200);
  syncSoon();
  await renderCampaignDetail();
  refreshDashboard();
});

$('delete-campaign-btn').addEventListener('click', async () => {
  if (!confirm('למחוק את הקמפיין?')) return;
  await Campaigns.remove(currentCampaignId);
  syncSoon();
  toast('נמחק', 'ok', 1200);
  showCampaignsList();
  refreshDashboard();
});

// Posts inside campaign

$('add-post-to-campaign-btn').addEventListener('click', () => openPostEditor(null));
$('cancel-post-btn').addEventListener('click', closePostEditor);
$('save-post-btn').addEventListener('click', savePost);

// Media attached to the post currently being edited.
// For new posts: rows are buffered with a temporary postId until the post is saved.
let editingPostMediaTempPostId = null;

async function openPostEditor(post) {
  editingPostId = post?.id || null;
  editingPostMediaTempPostId = post?.id || `tmp-${crypto.randomUUID()}`;
  $('post-title').value = post?.title || '';
  $('post-text').value = post?.text || '';
  $('post-weight').value = post?.weight || 1;
  $('post-type').value = post?.postType || 'text';
  $('post-color-index').value = String(post?.colorIndex ?? 0);
  $('post-link-url').value = post?.linkUrl || '';
  // Marketplace fields
  const md = post?.marketplaceData || {};
  $('mp-price').value = md.price ?? '';
  $('mp-currency').value = md.currency || 'ILS';
  $('mp-location').value = md.location || '';
  $('mp-category').value = md.category || 'general';
  $('mp-condition').value = md.condition || 'used-good';
  $('mp-brand').value = md.brand || '';
  $('mp-year').value = md.year ?? '';
  $('mp-make').value = md.make || '';
  $('mp-model').value = md.model || '';
  $('mp-mileage').value = md.mileage ?? '';
  $('mp-fuel').value = md.fuel || 'gasoline';
  $('mp-bedrooms').value = md.bedrooms ?? '';
  $('mp-sqft').value = md.sqft ?? '';
  $('mp-address').value = md.address || '';
  $('mp-property-type').value = md.propertyType || 'apartment';
  // New channel fields
  $('post-page-id').value = post?.targetPageId || '';
  $('post-share-url').value = post?.shareSourceUrl || '';
  const ev = post?.eventData || {};
  $('event-name').value = ev.name || '';
  $('event-when').value = ev.when ? tsToLocalInput(ev.when) : '';
  $('event-location').value = ev.location || '';
  $('event-privacy').value = ev.privacy || 'public';
  $('post-poll-question').value = post?.pollQuestion || '';
  renderPollOptions(post?.pollOptions || ['', '']);
  $('post-gif-query').value = post?.gifQuery || '';
  $('post-feeling').value = post?.feeling || 'happy';
  $('post-media-input').value = '';
  $('post-media-status').textContent = '';
  $('post-editor').hidden = false;
  updatePostTypeUI();
  updateTextCounter();
  await renderPostMediaThumbs();
}

function renderPollOptions(options) {
  const container = $('post-poll-options');
  container.innerHTML = '';
  options.forEach((opt, idx) => addPollOptionInput(opt, idx));
}

function addPollOptionInput(value = '', idx = null) {
  const container = $('post-poll-options');
  const wrap = document.createElement('div');
  wrap.style.cssText = 'display:flex;gap:4px;margin-bottom:4px';
  const input = document.createElement('input');
  input.type = 'text';
  input.placeholder = `תשובה ${(idx ?? container.children.length) + 1}`;
  input.value = value;
  input.className = 'poll-option-input';
  wrap.append(input);
  if (container.children.length >= 2) {
    const rm = document.createElement('button');
    rm.type = 'button';
    rm.textContent = '✕';
    rm.style.width = '32px';
    rm.addEventListener('click', () => wrap.remove());
    wrap.append(rm);
  }
  container.append(wrap);
}

$('add-poll-option-btn').addEventListener('click', () => addPollOptionInput());

// Show/hide sections based on type
function updatePostTypeUI() {
  const type = $('post-type').value;
  $('post-colored-opts').hidden = type !== 'colored';
  $('post-link-opts').hidden = type !== 'link';
  $('post-poll-opts').hidden = type !== 'poll';
  $('post-gif-opts').hidden = type !== 'gif';
  $('post-feeling-opts').hidden = type !== 'feeling';

  const isMP = type.startsWith('marketplace-');
  $('post-marketplace-opts').hidden = !isMP;
  $('mp-item-fields').hidden = type !== 'marketplace-item';
  $('mp-vehicle-fields').hidden = type !== 'marketplace-vehicle';
  $('mp-property-fields').hidden = !['marketplace-property-sale', 'marketplace-property-rent'].includes(type);

  // New channels
  $('post-page-opts').hidden = type !== 'page';
  $('post-share-opts').hidden = type !== 'share';
  $('post-event-opts').hidden = type !== 'event';

  // Media support per type
  const mediaTypes = ['text', 'feeling', 'link', 'profile', 'page', 'story', 'reel', 'album',
    'marketplace-item', 'marketplace-vehicle', 'marketplace-property-sale', 'marketplace-property-rent'];
  $('post-media-section').hidden = !mediaTypes.includes(type);
}

function updateTextCounter() {
  const len = $('post-text').value.length;
  const type = $('post-type').value;
  const c = $('post-text-counter');
  if (type === 'colored') {
    const ok = len <= 130;
    c.textContent = `${len}/130 תווים ${ok ? '✅' : '⚠ ארוך מדי לרקע צבעוני'}`;
    c.style.color = ok ? 'var(--muted)' : 'var(--danger)';
  } else {
    c.textContent = '';
  }
}

$('post-type').addEventListener('change', () => { updatePostTypeUI(); updateTextCounter(); });
$('post-text').addEventListener('input', updateTextCounter);

// ===== AI post generation =====
$('ai-generate-btn').addEventListener('click', async () => {
  const brief = $('ai-prompt').value.trim();
  if (!brief) { toast('כתוב על מה הפוסט', 'err'); return; }
  const btn = $('ai-generate-btn');
  btn.disabled = true; btn.classList.add('busy');
  const list = $('ai-variations');
  list.innerHTML = '<li class="muted">⏳ Gemini חושב...</li>';
  try {
    const { geminiGeneratePosts } = await import('../lib/gemini.js');
    const existing = $('ai-use-existing').checked
      ? (await Posts.listByCampaign(currentCampaignId)).map((p) => p.text).filter(Boolean)
      : [];
    const r = await geminiGeneratePosts({
      briefDescription: brief,
      existingExamples: existing,
      count: Math.min(5, Math.max(1, Number($('ai-count').value) || 3)),
      postType: $('post-type').value,
    });
    if (!r.ok) {
      list.innerHTML = `<li class="muted">❌ ${escapeHtml(r.error)}<br>(וודא ש-Gemini key מוגדר בהגדרות)</li>`;
      return;
    }
    list.innerHTML = '';
    if (!r.variations.length) {
      list.appendChild(emptyState('🤔', 'לא חזרו וריאציות', ''));
      return;
    }
    for (const v of r.variations) {
      const li = document.createElement('li');
      li.style.flexDirection = 'column';
      li.style.alignItems = 'stretch';
      li.style.gap = '4px';
      li.innerHTML = `
        <strong>${escapeHtml(v.title || '—')}</strong>
        <div class="muted" style="white-space:pre-wrap;font-size:11px;">${escapeHtml(v.text || '')}</div>
      `;
      const useBtn = mkBtn('✓ השתמש בזה', () => {
        $('post-title').value = v.title || ($('post-title').value || '');
        $('post-text').value = v.text || '';
        updateTextCounter();
        toast('הועתק לעורך', 'ok', 1500);
      });
      useBtn.className = 'primary';
      const saveBtn = mkBtn('💾 שמור כפוסט חדש', async () => {
        await Posts.save({
          campaignId: currentCampaignId,
          title: v.title || v.text.slice(0, 30),
          text: v.text,
          weight: 1,
          postType: $('post-type').value,
          colorIndex: Number($('post-color-index').value) || 0,
          mediaUrls: [],
          tags: [],
        });
        syncSoon();
        toast('נשמר בקמפיין', 'ok', 1500);
        renderCampaignPosts();
      });
      const row = document.createElement('div');
      row.className = 'row';
      row.style.margin = '4px 0 0';
      row.append(useBtn, saveBtn);
      li.appendChild(row);
      list.appendChild(li);
    }
  } catch (e) {
    list.innerHTML = `<li class="muted">❌ ${escapeHtml(String(e))}</li>`;
  } finally {
    btn.disabled = false; btn.classList.remove('busy');
  }
});
function closePostEditor() {
  $('post-editor').hidden = true;
  editingPostId = null;
  editingPostMediaTempPostId = null;
}

// File picker -> store as Blob in Media store, then re-render thumbs.
// Generate a matching image with Gemini based on the post text
$('ai-gen-image-btn').addEventListener('click', async () => {
  const text = $('post-text').value.trim();
  if (!text) { toast('כתוב טקסט קודם — Gemini ייצור תמונה תואמת', 'err'); return; }
  const customPrompt = prompt('תיאור התמונה (השאר ריק לתיאור אוטומטי מהפוסט):', '');
  if (customPrompt === null) return; // user cancelled
  const btn = $('ai-gen-image-btn');
  btn.disabled = true; btn.classList.add('busy');
  $('post-media-status').textContent = '⏳ Gemini יוצר תמונה...';
  try {
    const { geminiGenerateImage } = await import('../lib/gemini.js');
    const imgPrompt = customPrompt.trim() ||
      `תמונה אטרקטיבית, איכותית, בלי טקסט, שתתאים לפוסט פייסבוק הזה:\n${text.slice(0, 400)}\nסגנון: מודרני, חברי, מקצועי.`;
    const r = await geminiGenerateImage(imgPrompt);
    if (!r.ok) {
      $('post-media-status').textContent = `❌ ${r.error}`;
      return;
    }
    // Convert data URL to Blob and save as Media
    const resp = await fetch(r.dataUrl);
    const blob = await resp.blob();
    await Media.add({
      postId: editingPostMediaTempPostId,
      blob,
      mimeType: blob.type || 'image/png',
    });
    $('post-media-status').textContent = '✅ נוסף';
    await renderPostMediaThumbs();
    toast('תמונה נוצרה', 'ok', 2000);
  } catch (e) {
    $('post-media-status').textContent = `❌ ${String(e?.message || e)}`;
  } finally {
    btn.disabled = false; btn.classList.remove('busy');
  }
});

$('post-media-input').addEventListener('change', async (e) => {
  const files = Array.from(e.target.files || []);
  if (!files.length) return;
  $('post-media-status').textContent = `⏳ שומר ${files.length} קבצים...`;
  for (const f of files) {
    // Reject huge files — R2 free tier per-object is 5GB but practically
    // FB caps around 4GB anyway; let's warn above 50MB.
    if (f.size > 50 * 1024 * 1024) {
      toast(`${f.name} גדול מ-50MB — דלגתי`, 'err');
      continue;
    }
    const blob = await f.arrayBuffer().then((buf) => new Blob([buf], { type: f.type }));
    await Media.add({ postId: editingPostMediaTempPostId, blob, mimeType: f.type });
  }
  e.target.value = '';
  $('post-media-status').textContent = `✅ נוסף`;
  await renderPostMediaThumbs();
});

async function renderPostMediaThumbs() {
  const container = $('post-media-thumbs');
  container.innerHTML = '';
  const items = await Media.listByPost(editingPostMediaTempPostId);
  for (const m of items) {
    const objUrl = URL.createObjectURL(m.blob);
    const div = document.createElement('div');
    div.className = 'thumb';
    const isVideo = (m.mimeType || '').startsWith('video');
    div.innerHTML = `
      ${isVideo
        ? `<video src="${objUrl}" muted></video>`
        : `<img src="${objUrl}" alt="">`}
      <button class="remove" title="הסר">✕</button>
      <span class="badge-sync ${m.r2Key ? 'synced' : ''}">${m.r2Key ? '☁' : '⏳'}</span>
    `;
    div.querySelector('.remove').addEventListener('click', async () => {
      await Media.remove(m.id);
      URL.revokeObjectURL(objUrl);
      await renderPostMediaThumbs();
    });
    container.appendChild(div);
  }
}
async function savePost() {
  const text = $('post-text').value.trim();
  if (!text) { toast('טקסט הפוסט ריק', 'err'); return; }
  const existing = editingPostId ? await Posts.get(editingPostId) : {};
  const pollOpts = Array.from(document.querySelectorAll('.poll-option-input'))
    .map((i) => i.value.trim()).filter(Boolean);
  // Build marketplace payload if relevant
  const postType = $('post-type').value;
  let marketplaceData = null;
  let marketplaceCategory = null;
  if (postType.startsWith('marketplace-')) {
    marketplaceCategory = postType.replace('marketplace-', '');
    const base = {
      price: Number($('mp-price').value) || 0,
      currency: $('mp-currency').value,
      location: $('mp-location').value.trim(),
    };
    if (marketplaceCategory === 'item') {
      marketplaceData = { ...base,
        category: $('mp-category').value, condition: $('mp-condition').value,
        brand: $('mp-brand').value.trim() || null,
      };
    } else if (marketplaceCategory === 'vehicle') {
      marketplaceData = { ...base,
        year: Number($('mp-year').value) || null,
        make: $('mp-make').value.trim(), model: $('mp-model').value.trim(),
        mileage: Number($('mp-mileage').value) || null, fuel: $('mp-fuel').value,
      };
    } else if (marketplaceCategory.startsWith('property-')) {
      marketplaceData = { ...base,
        bedrooms: Number($('mp-bedrooms').value) || null,
        sqft: Number($('mp-sqft').value) || null,
        address: $('mp-address').value.trim(),
        propertyType: $('mp-property-type').value,
      };
    }
  }

  // Build event data
  let eventData = null;
  if (postType === 'event') {
    eventData = {
      name: $('event-name').value.trim(),
      when: localInputToTs($('event-when').value),
      location: $('event-location').value.trim() || null,
      privacy: $('event-privacy').value,
    };
  }

  const saved = await Posts.save({
    ...existing,
    campaignId: currentCampaignId,
    title: $('post-title').value.trim() || text.slice(0, 30),
    text,
    weight: Number($('post-weight').value) || 1,
    postType,
    colorIndex: Number($('post-color-index').value) || 0,
    linkUrl: $('post-link-url').value.trim() || null,
    pollQuestion: $('post-poll-question').value.trim() || null,
    pollOptions: pollOpts.length >= 2 ? pollOpts : null,
    gifQuery: $('post-gif-query').value.trim() || null,
    feeling: $('post-feeling').value || null,
    marketplaceCategory,
    marketplaceData,
    targetPageId: $('post-page-id').value.trim() || null,
    shareSourceUrl: $('post-share-url').value.trim() || null,
    eventData,
    mediaUrls: existing.mediaUrls || [],
    tags: existing.tags || [],
  });

  // If we were editing a new post under a tmp id, relink media to the real id.
  if (editingPostMediaTempPostId && editingPostMediaTempPostId !== saved.id) {
    const items = await Media.listByPost(editingPostMediaTempPostId);
    for (const m of items) {
      await Media.add({ postId: saved.id, blob: m.blob, mimeType: m.mimeType });
      await Media.remove(m.id);
    }
  }

  closePostEditor();
  syncSoon();
  toast('הפוסט נשמר', 'ok', 1200);
  renderCampaignPosts();
}

async function renderCampaignPosts() {
  const list = $('campaign-posts-list');
  const posts = await Posts.listByCampaign(currentCampaignId);
  list.innerHTML = '';
  if (!posts.length) {
    list.appendChild(emptyState('📝', 'אין פוסטים', 'הוסף לפחות 2 לגיוון'));
    return;
  }
  for (const p of posts) {
    const media = await Media.listByPost(p.id);
    const typeIcon = { text: '📝', colored: '🎨', link: '🔗', poll: '📊', gif: '🎉', feeling: '😊' }[p.postType || 'text'] || '📝';
    const lastUsed = p.lastUsedAt ? fmtTime(p.lastUsedAt) : 'אף פעם';
    const li = document.createElement('li');
    li.innerHTML = `
      <div class="row-main">
        <span title="סוג: ${p.postType || 'text'}">${typeIcon}</span>
        <span class="name">${escapeHtml(p.title)}</span>
        <div class="row-actions"></div>
      </div>
      <div class="row-preview" title="לחץ להרחבה">${escapeHtml(p.text || '')}</div>
      <div class="row-meta">
        <span>📊 ${p.useCount || 0}× שימושים</span>
        <span>⚖ משקל ${p.weight || 1}</span>
        ${media.length ? `<span>📷 ${media.length} מדיה</span>` : ''}
        <span>🕒 ${lastUsed}</span>
      </div>
    `;
    li.querySelector('.row-preview').addEventListener('click', (e) => e.currentTarget.classList.toggle('expanded'));
    const actions = li.querySelector('.row-actions');
    actions.appendChild(mkBtn('ערוך', () => openPostEditor(p)));
    actions.appendChild(mkBtn('🗑', async () => {
      if (confirm(`למחוק "${p.title}"?`)) {
        for (const m of media) await Media.remove(m.id);
        await Posts.remove(p.id);
        syncSoon();
        renderCampaignPosts();
      }
    }));
    list.appendChild(li);
  }
}

// Groups attached to campaign

$('campaign-groups-filter').addEventListener('input', renderCampaignGroups);

async function renderCampaignGroups() {
  const list = $('campaign-groups-list');
  const c = await Campaigns.get(currentCampaignId);
  const selected = new Set(c.groupIds || []);
  const filter = $('campaign-groups-filter').value.toLowerCase();
  const groups = (await Groups.list())
    .filter((g) => !filter || g.name?.toLowerCase().includes(filter))
    .sort((a, b) => (a.name || '').localeCompare(b.name || ''));
  list.innerHTML = '';
  if (!groups.length) {
    list.appendChild(emptyState('👥', 'אין קבוצות', 'עבור לטאב "קבוצות" ושאב'));
    return;
  }
  for (const g of groups) {
    const li = document.createElement('li');
    const cb = document.createElement('input');
    cb.type = 'checkbox';
    cb.checked = selected.has(g.id);
    cb.style.width = 'auto';
    cb.addEventListener('change', async () => {
      const fresh = await Campaigns.get(currentCampaignId);
      const set = new Set(fresh.groupIds || []);
      if (cb.checked) set.add(g.id); else set.delete(g.id);
      await Campaigns.update(fresh, { groupIds: Array.from(set) });
      syncSoon();
    });
    const name = document.createElement('span');
    name.className = 'name';
    name.textContent = g.name || g.fbGroupId;
    li.append(cb, name);
    list.appendChild(li);
  }
}

// ========== GROUPS ==========

document.querySelectorAll('[data-mode]').forEach((btn) => {
  btn.addEventListener('click', () => switchGroupsMode(btn.dataset.mode));
});
function switchGroupsMode(mode) {
  $('groups-mode-mine').classList.toggle('primary', mode === 'mine');
  $('groups-mode-discover').classList.toggle('primary', mode === 'discover');
  $('groups-mode-recommend').classList.toggle('primary', mode === 'recommend');
  $('groups-mine-view').hidden = mode !== 'mine';
  $('groups-discover-view').hidden = mode !== 'discover';
  $('groups-recommend-view').hidden = mode !== 'recommend';
  if (mode === 'discover') {
    renderSavedDiscoveries();
    restoreLastDiscoveryResults();
  }
}

async function renderSavedDiscoveries() {
  const list = $('discover-saved-list');
  const all = (await Discoveries.list()).sort((a, b) => (b.lastRunAt || 0) - (a.lastRunAt || 0));
  $('discover-saved-card').hidden = all.length === 0;
  list.innerHTML = '';
  for (const d of all) {
    const li = document.createElement('li');
    const lastRun = d.lastRunAt ? fmtTime(d.lastRunAt) : '—';
    li.innerHTML = `
      <span class="name">"${escapeHtml(d.query)}"</span>
      <span class="muted">${d.results?.length || 0} תוצאות · ${lastRun}</span>
      ${d.autoTrack ? '<span class="badge done">🔁 יומי</span>' : ''}
    `;
    li.appendChild(mkBtn('פתח', () => loadDiscoveryResults(d)));
    const trackBtn = mkBtn(d.autoTrack ? '⏸ בטל מעקב' : '🔁 עקוב יומי', async () => {
      await Discoveries.setAutoTrack(d.id, !d.autoTrack);
      toast(d.autoTrack ? 'מעקב בוטל' : 'יחפש כל יום אוטומטית', 'ok');
      syncSoon();
      renderSavedDiscoveries();
    });
    li.appendChild(trackBtn);
    li.appendChild(mkBtn('🗑', async () => {
      if (!confirm(`למחוק את החיפוש "${d.query}"?`)) return;
      await Discoveries.remove(d.id);
      syncSoon();
      renderSavedDiscoveries();
    }));
    list.appendChild(li);
  }
}

async function loadDiscoveryResults(discovery) {
  $('discover-keyword').value = discovery.query;
  $('discover-auto-track').checked = !!discovery.autoTrack;
  $('discover-status').textContent = `📚 טוען חיפוש שמור: "${discovery.query}" (${fmtTime(discovery.lastRunAt)})`;
  renderDiscoverResults(discovery.results || []);
}

async function restoreLastDiscoveryResults() {
  // Auto-load the most recent search when entering discover view
  const all = (await Discoveries.list()).sort((a, b) => (b.lastRunAt || 0) - (a.lastRunAt || 0));
  if (all.length && !$('discover-keyword').value) {
    const latest = all[0];
    $('discover-keyword').value = latest.query;
    $('discover-auto-track').checked = !!latest.autoTrack;
    $('discover-status').textContent = `📚 חיפוש אחרון: "${latest.query}" (${fmtTime(latest.lastRunAt)})`;
    renderDiscoverResults(latest.results || []);
  }
}

// ===== Recommendations =====

$('rec-search-btn').addEventListener('click', loadRecommendations);
$('rec-keyword').addEventListener('keydown', (e) => { if (e.key === 'Enter') loadRecommendations(); });

async function loadRecommendations() {
  const keyword = $('rec-keyword').value.trim();
  const minMembers = Number($('rec-min-members').value) || 0;
  const onlyInstantPost = $('rec-only-instant-post').checked;
  const onlyInstantJoin = $('rec-only-instant-join').checked;
  const btn = $('rec-search-btn');
  btn.disabled = true; btn.classList.add('busy');
  $('rec-status').textContent = '⏳ מחפש המלצות בענן...';
  $('rec-results').innerHTML = '';

  try {
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    const params = new URLSearchParams();
    if (keyword) params.set('keyword', keyword);
    if (minMembers) params.set('minMembers', String(minMembers));
    if (onlyInstantPost) params.set('postPolicy', 'instant');
    if (onlyInstantJoin) params.set('joinPolicy', 'instant');
    params.set('limit', '50');

    const res = await fetch(`${SYNC.endpoint}/recommendations?${params}`, {
      headers: { 'X-Session-Token': token },
    });
    const json = await res.json();
    if (!json.ok) {
      $('rec-status').textContent = '';
      toast(json.error || 'נכשל', 'err', 5000);
      return;
    }
    $('rec-status').textContent = `✅ ${json.recommendations.length} המלצות`;
    renderRecommendations(json.recommendations);
  } catch (e) {
    toast(String(e), 'err', 5000);
  } finally {
    btn.disabled = false; btn.classList.remove('busy');
  }
}

function renderRecommendations(recs) {
  const list = $('rec-results');
  list.innerHTML = '';
  if (!recs.length) {
    list.appendChild(emptyState('💡', 'אין המלצות עדיין', 'מסד הנתונים יתמלא ככל שלקוחות יפעילו'));
    return;
  }
  for (const r of recs) {
    const li = document.createElement('li');

    // Score pill
    const score = document.createElement('span');
    score.className = 'badge ' + (r.score >= 60 ? 'done' : r.score >= 30 ? 'running' : 'queued');
    score.textContent = `${r.score}`;
    score.title = 'ציון 0-100';
    li.append(score);

    const name = document.createElement('span');
    name.className = 'name';
    name.textContent = r.name || r.fb_group_id;
    li.append(name);

    if (r.member_count) li.append(spanMuted(`👥 ${fmtCount(r.member_count)}`));
    if (r.attempts > 0) li.append(spanMuted(`✓${r.successes}/${r.attempts}`));
    if (r.metric_count > 0) li.append(spanMuted(`⚡${r.avgEngagement} ממוצע`));
    if (r.unique_clients > 1) li.append(spanMuted(`👤${r.unique_clients}`));

    if (r.post_policy === 'instant') li.append(makeBadge('🚀', '', 'done'));
    else if (r.post_policy === 'approval') li.append(makeBadge('⏳', '', 'queued'));

    if (r.join_policy === 'instant') li.append(makeBadge('🤝', '', 'done'));
    else if (r.join_policy === 'approval') li.append(makeBadge('🔑', '', 'queued'));

    const openBtn = mkBtn('🔗', () => chrome.tabs.create({ url: r.url, active: true }));
    openBtn.title = 'פתח בטאב חדש';
    li.append(openBtn);

    const addBtn = mkBtn('➕', async () => {
      await Groups.upsertByFbId(r.fb_group_id, {
        name: r.name,
        url: r.url,
        memberCount: r.member_count,
        privacy: r.privacy,
        postPolicy: r.post_policy,
        joinPolicy: r.join_policy,
        source: 'recommended',
        isMember: 0,
      });
      toast('נוסף לקבוצות שלי', 'ok', 1200);
      syncSoon();
      refreshDashboard();
    });
    addBtn.title = 'הוסף לקבוצות שלי';
    li.append(addBtn);

    // ⭐ Want to join — queue for auto-join worker
    const wantBtn = mkBtn('⭐', async () => {
      await Groups.upsertByFbId(r.fb_group_id, {
        name: r.name, url: r.url,
        memberCount: r.member_count, privacy: r.privacy,
        postPolicy: r.post_policy, joinPolicy: r.join_policy,
        source: 'recommended', isMember: 0,
        wantToJoin: 1,
      });
      toast('סומן ⭐ — יצטרף אוטומטית בקרוב', 'ok', 2000);
      syncSoon();
    });
    wantBtn.title = 'סמן להצטרפות אוטומטית';
    li.append(wantBtn);

    list.appendChild(li);
  }
}

function spanMuted(text) {
  const s = document.createElement('span');
  s.className = 'muted';
  s.textContent = text;
  return s;
}

$('discover-btn').addEventListener('click', doDiscover);
$('discover-keyword').addEventListener('keydown', (e) => { if (e.key === 'Enter') doDiscover(); });

async function doDiscover() {
  const keyword = $('discover-keyword').value.trim();
  if (!keyword) { toast('הכנס מילת מפתח', 'err'); return; }
  const autoTrack = $('discover-auto-track').checked;
  $('discover-btn').disabled = true;
  $('discover-btn').classList.add('busy');
  $('discover-status').textContent = '⏳ פותח טאב חיפוש בפייסבוק, גולל ושואב תוצאות...';
  $('discover-results').innerHTML = '';
  try {
    const res = await chrome.runtime.sendMessage({ type: 'DISCOVER_GROUPS', payload: { keyword, autoTrack } });
    if (!res?.ok) {
      $('discover-status').textContent = '';
      toast(res?.error || 'נכשל', 'err', 5000);
      return;
    }
    $('discover-status').textContent = `✅ נמצאו ${res.count} קבוצות${autoTrack ? ' · 🔁 מעקב יומי הופעל' : ''}`;
    renderDiscoverResults(res.results);
    syncSoon();
    refreshDashboard();
    renderSavedDiscoveries();
  } finally {
    $('discover-btn').disabled = false;
    $('discover-btn').classList.remove('busy');
  }
}

const discoverSelected = new Set();

function renderDiscoverResults(results) {
  const list = $('discover-results');
  list.innerHTML = '';
  discoverSelected.clear();
  updateDiscoverBulkRow();

  const sorted = results.slice().sort((a, b) => {
    if (a.isMember !== b.isMember) return a.isMember ? 1 : -1;
    return (b.memberCount || 0) - (a.memberCount || 0);
  });
  if (!sorted.length) {
    list.appendChild(emptyState('🔍', 'אין תוצאות', 'נסה מילת מפתח אחרת'));
    return;
  }

  for (const r of sorted) {
    const li = document.createElement('li');

    // Checkbox to mark for bulk join (skip if already member)
    if (!r.isMember) {
      const cb = document.createElement('input');
      cb.type = 'checkbox';
      cb.style.width = 'auto';
      cb.addEventListener('change', async () => {
        // Need internal id — look up by fbGroupId
        const internal = await getInternalGroupIdByFbId(r.fbGroupId);
        if (!internal) return;
        if (cb.checked) discoverSelected.add(internal);
        else discoverSelected.delete(internal);
        updateDiscoverBulkRow();
      });
      li.append(cb);
    }

    const name = document.createElement('span');
    name.className = 'name';
    name.textContent = r.name;
    li.append(name);

    if (r.memberCount) {
      const m = document.createElement('span');
      m.className = 'muted';
      m.textContent = `👥 ${fmtCount(r.memberCount)}`;
      li.append(m);
    }
    if (r.privacy === 'public') li.append(makeBadge('🌐', 'ציבורית'));
    else if (r.privacy === 'private') li.append(makeBadge('🔒', 'פרטית'));
    if (r.joinPolicy === 'instant') li.append(makeBadge('🚀', 'מיידי', 'done'));
    else if (r.joinPolicy === 'approval') li.append(makeBadge('⏳', 'אישור', 'queued'));
    if (r.isMember) li.append(makeBadge('✅', 'חבר', 'done'));

    const openBtn = mkBtn('🔗', () => chrome.tabs.create({ url: r.url, active: true }));
    openBtn.title = 'פתח בטאב חדש';
    li.append(openBtn);

    if (!r.isMember) {
      // Check current wantToJoin state
      getInternalGroupIdByFbId(r.fbGroupId).then(async (internalId) => {
        if (!internalId) return;
        const g = await Groups.get(internalId);
        const isMarked = !!g?.wantToJoin;
        const wantBtn = document.createElement('button');
        wantBtn.className = isMarked ? 'primary' : '';
        wantBtn.style.cssText = 'padding:4px 10px; font-size:12px; white-space:nowrap;';
        wantBtn.textContent = isMarked ? '✓ נרשם להצטרפות' : '⭐ הירשם להצטרפות';
        wantBtn.title = isMarked ? 'בוטל מהתור של ההצטרפות האוטומטית' : 'יצטרף אוטומטית לקבוצה זו ברקע';
        wantBtn.addEventListener('click', async () => {
          const g2 = await Groups.get(internalId);
          const newState = g2?.wantToJoin ? 0 : 1;
          await Groups.upsertByFbId(r.fbGroupId, { ...g2, wantToJoin: newState });
          wantBtn.textContent = newState ? '✓ נרשם להצטרפות' : '⭐ הירשם להצטרפות';
          wantBtn.classList.toggle('primary', !!newState);
          toast(newState ? '✅ נרשם — יצטרף אוטומטית' : 'בוטל', 'ok');
          syncSoon();
        });
        li.append(wantBtn);
      });
    }

    list.appendChild(li);
  }
}

async function getInternalGroupIdByFbId(fbGroupId) {
  const groups = await Groups.list();
  return groups.find((g) => g.fbGroupId === fbGroupId)?.id || null;
}

function updateDiscoverBulkRow() {
  const n = discoverSelected.size;
  $('discover-bulk-row').hidden = n === 0;
  $('discover-selected-count').textContent = `${n} קבוצות מסומנות`;
}

$('join-selected-btn').addEventListener('click', async () => {
  if (!discoverSelected.size) return;
  const ids = Array.from(discoverSelected);
  if (!confirm(`להצטרף ל-${ids.length} קבוצות?\n\nהפעולה תיקח ~${Math.round(ids.length * 2.5)} דקות (השהיה של 90-180 שניות בין הצטרפויות, להימנע מחסימה).`)) return;
  const btn = $('join-selected-btn');
  btn.disabled = true; btn.classList.add('busy');
  $('discover-status').textContent = '🤝 מצטרף לקבוצות...';
  const res = await chrome.runtime.sendMessage({ type: 'JOIN_GROUPS', payload: { groupIds: ids } });
  btn.disabled = false; btn.classList.remove('busy');
  if (res?.ok) {
    const r = res.results;
    $('discover-status').textContent = `✅ הסתיים: ${r.instant} מיידי, ${r.approval} ממתין לאישור, ${r.alreadyMember} כבר חבר, ${r.failed} נכשל`;
    toast('הצטרפות הושלמה', 'ok', 4000);
    syncSoon();
    refreshDashboard();
    discoverSelected.clear();
    updateDiscoverBulkRow();
  } else {
    toast(res?.error || 'נכשל', 'err', 5000);
  }
});

$('scrape-groups-btn').addEventListener('click', scrapeGroups);
$('groups-filter').addEventListener('input', renderGroups);

async function scrapeGroups() {
  $('scrape-groups-btn').disabled = true;
  obLog.event('scrape_groups_start');
  toast('🔍 פותח את דף הקבוצות שלך...', 'ok', 2500);
  try {
    // Self-navigate: if we're already on the joins page, reuse it;
    // otherwise open a new tab and wait for it to finish loading.
    let tab = null;
    const existing = await chrome.tabs.query({ url: '*://*.facebook.com/groups/joins/*' });
    if (existing.length > 0) {
      tab = existing[0];
      // Don't steal focus — keep the plugin view on top while we scrape.
    } else {
      // Open in the BACKGROUND (active:false) so the popup/plugin stays on top.
      tab = await chrome.tabs.create({ url: 'https://www.facebook.com/groups/joins/', active: false });
      // Wait for the tab to finish loading (FB groups page can take 3-6s)
      await new Promise((resolve) => {
        const listener = (tabId, info) => {
          if (tabId === tab.id && info.status === 'complete') {
            chrome.tabs.onUpdated.removeListener(listener);
            resolve();
          }
        };
        chrome.tabs.onUpdated.addListener(listener);
        // Safety timeout — 15s
        setTimeout(() => { chrome.tabs.onUpdated.removeListener(listener); resolve(); }, 15000);
      });
      // Extra settle time — FB lazy-loads the list
      await new Promise(r => setTimeout(r, 1500));
    }
    const res = await chrome.tabs.sendMessage(tab.id, { type: 'SCRAPE_MY_GROUPS' });
    if (res?.ok) {
      obLog.event('scrape_groups_ok', { context: { count: res.groups.length } });
      toast(`✓ נמצאו ${res.groups.length} קבוצות`, 'ok');
      syncSoon();
      renderGroups();
      refreshDashboard();
    } else {
      obLog.error('scrape_groups_failed', { context: { error: res?.error } });
      toast(res?.error || 'שגיאה לא ידועה', 'err', 5000);
    }
  } catch (e) {
    obLog.error('scrape_groups_exception', { context: { msg: String(e?.message || e) } });
    toast('❌ ' + String(e?.message || e), 'err', 5000);
  } finally {
    $('scrape-groups-btn').disabled = false;
  }
}

async function renderGroups() {
  const list = $('groups-list');
  const filter = $('groups-filter').value.toLowerCase();
  const groups = (await Groups.list())
    .filter((g) => !filter || g.name?.toLowerCase().includes(filter))
    .sort((a, b) => (a.name || '').localeCompare(b.name || ''));
  list.innerHTML = '';
  if (!groups.length) {
    list.appendChild(emptyState('👥', 'אין קבוצות', 'הרץ "שאב את הקבוצות שלי"'));
    return;
  }
  for (const g of groups) {
    list.appendChild(renderGroupLi(g));
  }
}

function renderGroupLi(g) {
  const li = document.createElement('li');
  const lastPosted = g.lastPostedAt ? fmtTime(g.lastPostedAt) : 'מעולם לא';
  const lastScraped = g.lastScrapedAt ? fmtTime(g.lastScrapedAt) : '—';

  // Avatar
  const avatar = g.avatarUrl
    ? `<img class="group-avatar" src="${escapeHtml(g.avatarUrl)}" alt="" onerror="this.style.display='none'" />`
    : `<div class="group-avatar-placeholder">👥</div>`;

  // Main row with avatar
  const main = document.createElement('div');
  main.className = 'row-main';
  main.innerHTML = `
    ${avatar}
    <span class="name">${escapeHtml(g.name || g.fbGroupId)}</span>
    <div class="row-actions">
      <a href="${escapeHtml(g.url || '#')}" target="_blank" title="פתח בפייסבוק" style="text-decoration:none;font-size:14px;">🔗</a>
    </div>
  `;
  li.append(main);

  // Description preview (if available)
  if (g.description) {
    const desc = document.createElement('div');
    desc.className = 'row-preview';
    desc.title = 'לחץ להרחבה';
    desc.textContent = g.description;
    desc.addEventListener('click', (e) => e.currentTarget.classList.toggle('expanded'));
    li.append(desc);
  }

  // Meta line 1 — primary attributes
  const meta = document.createElement('div');
  meta.className = 'row-meta';
  const parts = [];
  if (g.memberCount) parts.push(`<span>👥 <b>${fmtCount(g.memberCount)}</b></span>`);
  if (g.privacy === 'public') parts.push('<span class="badge done">🌐 ציבורית</span>');
  else if (g.privacy === 'private') parts.push('<span class="badge queued">🔒 פרטית</span>');
  if (g.postPolicy === 'instant') parts.push('<span class="badge done">🚀 פרסום מיידי</span>');
  else if (g.postPolicy === 'approval') parts.push('<span class="badge queued">⏳ פרסום באישור</span>');
  if (g.joinPolicy === 'instant') parts.push('<span class="badge done">🤝 הצטרפות מיידית</span>');
  else if (g.joinPolicy === 'approval') parts.push('<span class="badge queued">🔑 הצטרפות באישור</span>');
  if (g.restrictionLevel) {
    const lbl = { low: '🟢 קל', medium: '🟡 בינוני', high: '🔴 קשה' }[g.restrictionLevel] || g.restrictionLevel;
    parts.push(`<span class="badge restr-${g.restrictionLevel}">${lbl}</span>`);
  }
  meta.innerHTML = parts.join('');
  li.append(meta);

  // Meta line 2 — secondary attributes
  const meta2 = document.createElement('div');
  meta2.className = 'row-meta';
  const parts2 = [];
  if (g.location) parts2.push(`<span>📍 ${escapeHtml(g.location)}</span>`);
  if (g.language) parts2.push(`<span>🗣 ${g.language}</span>`);
  if (g.postsPerDay) parts2.push(`<span>📊 ${g.postsPerDay} פוסטים/יום</span>`);
  if (g.adminCount) parts2.push(`<span>👮 ${g.adminCount} מנהלים</span>`);
  parts2.push(`<span>🕒 פרסום אחרון: ${lastPosted}</span>`);
  if (g.source && g.source !== 'manual') parts2.push(`<span>📂 ${g.source}</span>`);
  if (g.wantToJoin) parts2.push('<span class="badge queued">⭐ בתור להצטרפות</span>');
  meta2.innerHTML = parts2.join('');
  li.append(meta2);

  return li;
}

function makeBadge(emoji, text, cls = '') {
  const b = document.createElement('span');
  b.className = `badge ${cls}`;
  b.textContent = `${emoji} ${text}`;
  return b;
}

function fmtCount(n) {
  if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
  if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
  return String(n);
}

// ========== QUEUE ==========

$('refresh-queue-btn').addEventListener('click', renderQueue);
$('cancel-all-queued-btn').addEventListener('click', async () => {
  const queued = (await Jobs.list()).filter((j) => j.status === 'queued');
  if (!queued.length) { toast('אין משימות ממתינות', 'ok'); return; }
  if (!confirm(`לבטל ${queued.length} משימות ממתינות?`)) return;
  for (const j of queued) await Jobs.update(j, { status: 'cancelled' });
  toast(`בוטלו ${queued.length} משימות`, 'ok');
  syncSoon();
  renderQueue();
  refreshDashboard();
});

$('clear-failed-btn').addEventListener('click', async () => {
  const failed = (await Jobs.list()).filter((j) => j.status === 'failed');
  if (!failed.length) { toast('אין כשלונות לניקוי', 'ok'); return; }
  if (!confirm(`למחוק לצמיתות ${failed.length} משימות שנכשלו?`)) return;
  for (const j of failed) await Jobs.remove(j.id);
  toast(`נמחקו ${failed.length}`, 'ok');
  syncSoon();
  renderQueue();
  refreshDashboard();
});

$('mark-all-done-btn').addEventListener('click', async () => {
  if (!confirm('לסמן את כל המשימות שנכשלו כהושלמו? (להשתמש רק אם הפרסום באמת הצליח בפייסבוק)')) return;
  const r = await chrome.runtime.sendMessage({ type: 'MARK_ALL_FAILED_DONE' });
  if (r?.ok) {
    toast(`סומנו ${r.count} משימות כהושלמו`, 'ok');
    syncSoon();
    renderQueue();
    refreshDashboard();
  } else {
    toast(r?.error || 'נכשל', 'err');
  }
});

$('run-next-btn').addEventListener('click', async () => {
  if (!confirm('להריץ את המשימה הבאה מיד? (עוקף את ה-throttler — לדיבוג בלבד)')) return;
  const res = await chrome.runtime.sendMessage({ type: 'RUN_NEXT_NOW' });
  if (res?.ok) toast('הורץ בהצלחה', 'ok');
  else toast(res?.error || 'נכשל', 'err', 5000);
  renderQueue();
  refreshDashboard();
});

async function renderQueueETA() {
  const r = await chrome.runtime.sendMessage({ type: 'QUEUE_ETA' });
  const box = $('queue-eta');
  if (!r?.ok || !r.nextAt) { box.hidden = true; return; }
  const minutes = Math.max(0, Math.round((r.nextAt - Date.now()) / 60000));
  box.hidden = false;
  if (minutes === 0) {
    box.innerHTML = `<strong>⏱ המשימה הבאה תרוץ ברגעים הקרובים</strong> <span class="muted">(ה-service worker בודק כל דקה)</span>`;
  } else {
    const eta = new Date(r.nextAt).toLocaleTimeString('he-IL', { hour: '2-digit', minute: '2-digit' });
    box.innerHTML = `<strong>⏱ המשימה הבאה: בעוד ${minutes} דק' (בערך ${eta})</strong>
      <p class="muted">ה-throttler האנושי מחזיק זמן בין פוסטים. אם אתה רוצה לבדוק מיד, השתמש ב-🐞 "הרץ עכשיו".</p>`;
  }
}

async function renderQueue() {
  await renderQueueETA();
  const list = $('queue-list');
  const jobs = (await Jobs.list()).sort((a, b) => (b.scheduledAt || 0) - (a.scheduledAt || 0));
  const counts = jobs.reduce((acc, j) => { acc[j.status] = (acc[j.status] || 0) + 1; return acc; }, {});
  $('queue-summary').textContent = `⏳ ${counts.queued || 0} | 🏃 ${counts.running || 0} | ✅ ${counts.done || 0} | ❌ ${counts.failed || 0}`;
  list.innerHTML = '';
  if (!jobs.length) {
    list.appendChild(emptyState('📭', 'התור ריק', 'הפעל קמפיין כדי להוסיף משימות'));
    return;
  }
  for (const j of jobs.slice(0, 100)) {
    const g = await Groups.get(j.groupId);
    const c = j.campaignId ? await Campaigns.get(j.campaignId) : null;
    const chosenPost = j.chosenPostId ? await Posts.get(j.chosenPostId) : null;
    const li = document.createElement('li');
    const errMsg = j.lastError ? `<div class="row-preview" style="background:var(--danger-soft);color:var(--danger);">${escapeHtml(j.lastError)}</div>` : '';
    const postPreview = chosenPost ? `<div class="row-preview" title="לחץ להרחבה">${escapeHtml(chosenPost.text || chosenPost.title || '')}</div>` : '';
    li.innerHTML = `
      <div class="row-main">
        <span class="name">${escapeHtml(g?.name || j.groupId)}</span>
        <span class="badge ${j.status}">${j.status}</span>
        <div class="row-actions"></div>
      </div>
      ${postPreview}
      ${errMsg}
      <div class="row-meta">
        ${c?.name ? `<span>📁 ${escapeHtml(c.name)}</span>` : ''}
        ${chosenPost ? `<span>📝 ${escapeHtml(chosenPost.title)}</span>` : ''}
        <span>🕒 ${fmtTime(j.scheduledAt)}</span>
        ${j.completedAt ? `<span>✅ ${fmtTime(j.completedAt)}</span>` : ''}
        ${j.attempts > 1 ? `<span>🔄 ${j.attempts} נסיונות</span>` : ''}
      </div>
    `;
    li.querySelectorAll('.row-preview').forEach((el) => el.addEventListener('click', (e) => e.currentTarget.classList.toggle('expanded')));
    const actions = li.querySelector('.row-actions');
    li.dataset.actionsHost = '1';
    // overwrite later
    if (j.status === 'queued') {
      actions.appendChild(mkBtn('בטל', async () => {
        await Jobs.update(j, { status: 'cancelled' });
        syncSoon();
        renderQueue();
      }));
    } else if (['failed', 'done', 'cancelled'].includes(j.status)) {
      actions.appendChild(mkBtn('↻', async () => {
        const r = await chrome.runtime.sendMessage({ type: 'REQUEUE_JOB', payload: { jobId: j.id } });
        if (r?.ok) {
          toast('הוחזר לתור', 'ok', 1200);
          syncSoon();
          renderQueue();
          refreshDashboard();
        } else {
          toast(r?.error || 'נכשל', 'err', 5000);
        }
      }));
      if (j.status === 'failed') {
        actions.appendChild(mkBtn('✅', async () => {
          const r = await chrome.runtime.sendMessage({ type: 'MARK_DONE', payload: { jobId: j.id } });
          if (r?.ok) {
            toast('סומן כהושלם', 'ok', 1200);
            syncSoon();
            renderQueue();
            refreshDashboard();
          }
        }));
      }
    }
    list.appendChild(li);
  }
}

// ========== LOGS ==========

let logsSource = 'local'; // 'local' or 'server'
$('refresh-logs-btn').addEventListener('click', renderLogs);
$('logs-toggle-btn').addEventListener('click', () => {
  logsSource = logsSource === 'local' ? 'server' : 'local';
  $('logs-toggle-btn').textContent = logsSource === 'local' ? '☁ מהשרת' : '🏠 מקומי';
  $('logs-source-label').textContent = logsSource === 'local' ? 'מקומי' : 'מהשרת';
  renderLogs();
});

async function renderLogs() {
  const list = $('logs-list');
  list.innerHTML = '<li class="muted">⏳ טוען...</li>';
  let logs = [];
  if (logsSource === 'local') {
    logs = await Logs.list(100);
  } else {
    try {
      const { token } = await (await import('../lib/auth.js')).getSession();
      const res = await fetch(`${(await import('../lib/config.js')).SYNC.endpoint}/logs?limit=100`, {
        headers: { 'X-Session-Token': token },
      });
      const json = await res.json();
      logs = (json.logs || []).map((l) => ({
        id: l.id,
        level: l.level,
        message: l.message,
        createdAt: l.created_at,
      }));
    } catch (e) {
      list.innerHTML = `<li class="muted">❌ שגיאה: ${escapeHtml(String(e))}</li>`;
      return;
    }
  }
  list.innerHTML = '';
  if (!logs.length) {
    list.appendChild(emptyState('📋', 'אין לוגים', ''));
    return;
  }
  for (const l of logs) {
    const li = document.createElement('li');
    li.innerHTML = `
      <span class="badge ${l.level === 'error' ? 'failed' : 'done'}">${l.level}</span>
      <span class="name">${escapeHtml(l.message)}</span>
      <span class="muted">${fmtTime(l.createdAt)}</span>
    `;
    list.appendChild(li);
  }
}

// ========== SETTINGS ==========
// We map UI fields <-> throttleConfig. `cfg-meanMin` is in MINUTES for UX,
// but stored as seconds via interPostMeanSec.

async function refreshGeminiStatus() {
  const key = await getGeminiKey();
  const pill = $('gemini-status');
  const verifiedSpan = $('gemini-verified-at');
  if (!key) {
    // No LOCAL key — but the key lives server-side (D1) and survives a reinstall.
    // Ask the server: if it still has the key, the AI works without re-entry, so
    // reflect "connected" and restore the local verified marker.
    try {
      const s = await aiApi('/gemini/key');
      if (s?.ok && s.hasKey) {
        if (s.verifiedAt) { try { await setSetting('gemini.verifiedAt', s.verifiedAt); } catch {} }
        pill.textContent = '🟢 מחובר (נשמר בחשבון)';
        pill.className = 'pill ok';
        verifiedSpan.textContent = 'המפתח נשמר בשרת — אין צורך להזין מחדש';
        return;
      }
    } catch {}
    pill.textContent = '🔴 לא מחובר';
    pill.className = 'pill';
    verifiedSpan.textContent = '';
    return;
  }
  const verifiedAt = await getSetting('gemini.verifiedAt');
  if (verifiedAt) {
    pill.textContent = '🟢 מחובר ומאומת';
    pill.className = 'pill ok';
    const min = Math.floor((Date.now() - verifiedAt) / 60000);
    verifiedSpan.textContent = `אומת לפני ${min < 1 ? 'פחות מדקה' : `${min} דק'`}`;
  } else {
    pill.textContent = '🟡 מפתח שמור, לא נבדק';
    pill.className = 'pill warn';
    verifiedSpan.textContent = 'לחץ "בדוק חיבור"';
  }
}

$('gemini-open-studio').addEventListener('click', () => {
  chrome.tabs.create({ url: 'https://aistudio.google.com/apikey', active: true });
  toast('הכנס לאתר, צור API Key, חזור והדבק כאן', 'ok', 4000);
});

$('gemini-save-btn').addEventListener('click', async () => {
  const key = $('gemini-key-input').value.trim();
  if (!key) { toast('הדבק מפתח קודם', 'err'); return; }
  if (!key.startsWith('AIza')) {
    if (!confirm('המפתח לא מתחיל ב-AIza — בטח שזה מפתח Gemini תקין?')) return;
  }
  obLog.event('gemini_save_start', { context: { len: key.length, prefix_ok: key.startsWith('AIza') } });
  const btn = $('gemini-save-btn');
  btn.disabled = true; btn.classList.add('busy');
  const saved = await saveGeminiKey(key);
  if (!saved.ok) {
    btn.disabled = false; btn.classList.remove('busy');
    obLog.error('gemini_save_server_rejected', { context: { error: saved.error } });
    toast(`❌ ${saved.error}`, 'err', 9000);
    refreshGeminiStatus();
    return;
  }
  const r = await testGeminiKey();
  btn.disabled = false; btn.classList.remove('busy');
  if (r.ok) {
    obLog.event('gemini_save_ok', { context: { echo: r.modelEcho } });
    toast(`✅ Gemini מחובר! תשובה: "${r.modelEcho}"`, 'ok', 3000);
    $('gemini-key-input').value = '';
  } else {
    obLog.error('gemini_save_test_failed', { context: { error: r.error } });
    toast(`❌ בדיקה נכשלה: ${r.error}`, 'err', 8000);
  }
  refreshGeminiStatus();
});

$('gemini-test-btn').addEventListener('click', async () => {
  obLog.event('gemini_test_start');
  const r = await testGeminiKey();
  if (r.ok) { obLog.event('gemini_test_ok'); toast(`✅ עובד! "${r.modelEcho}"`, 'ok'); }
  else { obLog.error('gemini_test_failed', { context: { error: r.error } }); toast(`❌ ${r.error}`, 'err', 8000); }
  refreshGeminiStatus();
});

$('gemini-clear-btn').addEventListener('click', async () => {
  if (!confirm('להסיר את מפתח Gemini? תאבד את היכולת לפיצ\'רים חכמים.')) return;
  obLog.event('gemini_clear');
  await clearGeminiKey();
  toast('המפתח הוסר', 'ok');
  refreshGeminiStatus();
});

// === Logging status (read-only — managed from dashboard) ===
async function refreshLoggingToggle() {
  const el = $('logging-status');
  if (!el) return;
  try {
    const { token } = await getSession();
    if (!token) { el.textContent = 'התחבר/י קודם'; return; }
    const r = await fetch(`${SYNC.endpoint}/logging/pref`, { headers: { 'X-Session-Token': token } });
    const j = await r.json();
    el.textContent = j.enabled !== false
      ? '✅ פעיל — שגיאות ופעולות נשלחות לשרת'
      : '⏸ כבוי — אפשר להפעיל מהדשבורד';
  } catch {
    el.textContent = 'לא הצלחתי לבדוק סטטוס (אין רשת?)';
  }
}

// === API Keys management ===
async function loadApiKeys() {
  const { token } = await getSession();
  if (!token) return;
  try {
    const res = await fetch(`${SYNC.endpoint}/api/keys`, { headers: { 'X-Session-Token': token } });
    const json = await res.json();
    const list = $('api-keys-list');
    list.innerHTML = '';
    if (!json.ok || !json.keys?.length) {
      list.innerHTML = '<li class="muted" style="padding:8px;">אין מפתחות עדיין</li>';
      return;
    }
    for (const k of json.keys) {
      const li = document.createElement('li');
      li.style.cssText = 'padding:8px; border-bottom:1px solid var(--border); display:flex; justify-content:space-between; align-items:center; gap:8px;';
      const revoked = k.revoked ? ' <span style="color:#c00;">[בוטל]</span>' : '';
      const lastUsed = k.last_used_at ? new Date(k.last_used_at).toLocaleDateString('he-IL') : 'אף פעם';
      li.innerHTML = `<div style="flex:1; min-width:0;">
        <strong>${escapeHtml(k.name || 'ללא שם')}</strong>${revoked}<br>
        <code style="font-size:11px;">${escapeHtml(k.key_prefix)}…</code>
        <span class="muted" style="font-size:11px;"> · ${escapeHtml(k.scopes)} · ${k.rate_limit}/שעה · שימוש: ${lastUsed}</span>
      </div>`;
      if (!k.revoked) {
        const btn = document.createElement('button');
        btn.className = 'danger';
        btn.textContent = 'בטל';
        btn.addEventListener('click', async () => {
          if (!confirm(`לבטל את המפתח "${k.name}"?`)) return;
          await fetch(`${SYNC.endpoint}/api/keys/${k.id}`, { method: 'DELETE', headers: { 'X-Session-Token': token } });
          toast('המפתח בוטל', 'ok');
          loadApiKeys();
        });
        li.appendChild(btn);
      }
      list.appendChild(li);
    }
  } catch (e) {
    console.warn('loadApiKeys failed', e);
  }
}

// escapeHtml is defined later in the file — reused.

$('api-key-create-btn')?.addEventListener('click', async () => {
  const { token } = await getSession();
  if (!token) { toast('לא מחובר', 'err'); return; }
  const name = $('api-key-name').value.trim() || 'Untitled';
  const scopes = $('api-key-scopes').value;
  try {
    const res = await fetch(`${SYNC.endpoint}/api/keys`, {
      method: 'POST',
      headers: { 'X-Session-Token': token, 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, scopes }),
    });
    const json = await res.json();
    if (!json.ok) { toast(json.error || 'יצירה נכשלה', 'err'); return; }
    $('api-key-new-value').textContent = json.key;
    $('api-key-new').style.display = 'block';
    $('api-key-name').value = '';
    toast('המפתח נוצר — העתק עכשיו!', 'ok');
    loadApiKeys();
  } catch (e) {
    toast('שגיאה: ' + e.message, 'err');
  }
});

$('api-key-copy-btn')?.addEventListener('click', () => {
  const val = $('api-key-new-value').textContent;
  navigator.clipboard.writeText(val).then(() => toast('הועתק ✓', 'ok'));
});

$('api-key-new-dismiss')?.addEventListener('click', () => {
  $('api-key-new').style.display = 'none';
  $('api-key-new-value').textContent = '';
});

async function loadSettings() {
  const res = await chrome.runtime.sendMessage({ type: 'GET_THROTTLE_CONFIG' });
  const cfg = { ...DEFAULTS, ...(res?.config || {}) };
  await refreshGeminiStatus();
  await refreshLoggingToggle();
  $('ai-autogen-toggle').checked = !!(await getSetting('aiAutoGenerate', true));
  $('ai-safety-toggle').checked = !!(await getSetting('aiSafetyCheck', true));
  $('ai-target-count').value = (await getSetting('aiTargetPostCount', 8));
  $('auto-join-toggle').checked = !!(await getSetting('autoJoinEnabled', false));
  $('ai-join-safety-toggle').checked = !!(await getSetting('aiJoinSafetyCheck', true));
  $('auto-join-daily-cap').value = (await getSetting('autoJoinDailyCap', 8));
  $('auto-join-weekly-cap').value = (await getSetting('autoJoinWeeklyCap', 35));
  // Show join history status
  const history = (await getSetting('autoJoinHistory', [])) || [];
  const now = Date.now();
  const day = 86400000;
  const today = history.filter((t) => now - t < day).length;
  const week = history.filter((t) => now - t < 7 * day).length;
  const dailyCap = await getSetting('autoJoinDailyCap', 8);
  const weeklyCap = await getSetting('autoJoinWeeklyCap', 35);
  $('auto-join-history-status').textContent = `📊 הצטרפויות: ${today}/${dailyCap} היום · ${week}/${weeklyCap} השבוע`;
  $('auto-bump-toggle').checked = !!(await getSetting('autoBumpEnabled', false));
  $('auto-bump-text').value = (await getSetting('autoBumpText')) || 'מעלה למעלה ⬆ שיגיע לכמה שיותר אנשים';
  $('evening-refresh-toggle').checked = !!(await getSetting('eveningRefreshEnabled', true));
  $('evening-refresh-hour').value = (await getSetting('eveningRefreshHour', 21));
  $('li-first-comment-toggle').checked = !!(await getSetting('liFirstCommentEnabled', true));
  $('li-first-comment-text').value = (await getSetting('liFirstCommentText')) || 'מצרף קישור עם תוכן נוסף בנושא בתגובה הראשונה 👇';
  $('comments-enabled-toggle').checked = !!(await getSetting('commentsEnabled', true));
  // LinkedIn growth pass settings
  $('li-growth-toggle').checked = !!(await getSetting('liGrowthEnabled', false));
  const kws = (await getSetting('liGrowthKeywords', [])) || [];
  $('li-growth-keywords').value = Array.isArray(kws) ? kws.join('\n') : '';
  $('li-growth-max-likes').value = Number(await getSetting('liGrowthMaxLikes', 3)) || 3;
  $('li-growth-start-hour').value = Number(await getSetting('liGrowthStartHour', 9)) || 9;
  $('li-growth-end-hour').value = Number(await getSetting('liGrowthEndHour', 19)) || 19;
  $('li-growth-comment-toggle').checked = !!(await getSetting('liGrowthCommentEnabled', false));
  $('li-growth-ai-comment-toggle').checked = !!(await getSetting('liGrowthAiCommentEnabled', false));
  $('li-growth-comment-text').value = (await getSetting('liGrowthCommentText', '')) || '';
  $('li-growth-user-expertise').value = (await getSetting('userExpertise', '')) || '';
  // Twitter growth pass settings
  $('tw-growth-toggle').checked = !!(await getSetting('twGrowthEnabled', false));
  const twKws = (await getSetting('twGrowthKeywords', [])) || [];
  $('tw-growth-keywords').value = Array.isArray(twKws) ? twKws.join('\n') : '';
  $('tw-growth-max-likes').value = Number(await getSetting('twGrowthMaxLikes', 5)) || 5;
  $('tw-growth-start-hour').value = Number(await getSetting('twGrowthStartHour', 9)) || 9;
  $('tw-growth-end-hour').value = Number(await getSetting('twGrowthEndHour', 22)) || 22;
  try {
    const twIdx = Number(await getSetting('twGrowthKeywordIdx', 0)) || 0;
    const nextTwKw = (twKws.length && Array.isArray(twKws)) ? twKws[twIdx % twKws.length] : '—';
    $('tw-growth-status').textContent = $('tw-growth-toggle').checked
      ? `🟢 הריצה הבאה: "${nextTwKw}"`
      : '🔴 מושבת';
  } catch {}
  // LinkedIn auto-reply settings
  $('li-auto-reply-toggle').checked = !!(await getSetting('liAutoReplyEnabled', false));
  $('li-auto-reply-self-handle').value = (await getSetting('liSelfHandle', '')) || '';
  try {
    const tracking = (await getSetting('liAutoReplyTracking', {})) || {};
    let totalReplies = 0;
    for (const jobId of Object.keys(tracking)) {
      totalReplies += Object.keys(tracking[jobId] || {}).length;
    }
    $('li-auto-reply-status').textContent = $('li-auto-reply-toggle').checked
      ? `🟢 פעיל · ${totalReplies} תשובות נשלחו עד עכשיו (7 ימים אחרונים)`
      : '🔴 מושבת';
  } catch {}
  // Status line for the growth pass — show next-run window + recent activity hint
  try {
    const liWarnAt = Number(await getSetting('lastLinkedInWarningAt', 0)) || 0;
    const liBackoff = Number(await getSetting('linkedinBackoffMs', 24 * 3600 * 1000)) || (24 * 3600 * 1000);
    const idx = Number(await getSetting('liGrowthKeywordIdx', 0)) || 0;
    const nextKw = (kws.length && Array.isArray(kws)) ? kws[idx % kws.length] : '—';
    const statusBits = [];
    if (!$('li-growth-toggle').checked) statusBits.push('🔴 מושבת');
    else {
      statusBits.push(`🟢 הריצה הבאה: "${nextKw}"`);
      if (liWarnAt && Date.now() - liWarnAt < liBackoff) {
        const hLeft = Math.ceil((liBackoff - (Date.now() - liWarnAt)) / 3600000);
        statusBits.push(`🛑 backoff פעיל עוד ${hLeft}ש'`);
      }
    }
    $('li-growth-status').textContent = statusBits.join(' · ');
  } catch {}
  loadApiKeys();
  // Comments queue status
  const cq = (await Comments.list()).filter((c) => c.status === 'queued');
  $('comments-queue-status').textContent = cq.length ? `${cq.length} תגובות בתור` : 'תור ריק';
  // Auto-join status hint
  const wanted = (await Groups.list()).filter((g) => g.wantToJoin && !g.isMember);
  const lastWarnAt = await getSetting('lastFbWarningAt', 0);
  const backoff = await getSetting('warningBackoffMs', 0);
  let hint = `${wanted.length} קבוצות בתור להצטרפות`;
  if (lastWarnAt && backoff && Date.now() - lastWarnAt < backoff) {
    const hLeft = Math.ceil((backoff - (Date.now() - lastWarnAt)) / 3600000);
    hint += ` · 🛑 backoff פעיל עוד ${hLeft}ש'`;
  }
  $('auto-join-status').textContent = hint;
  $('cfg-meanMin').value = Math.round(cfg.interPostMeanSec / 60);
  $('cfg-stddev').value = cfg.interPostStddevSec;
  $('cfg-startH').value = cfg.activeHourStart;
  $('cfg-endH').value = cfg.activeHourEnd;
  $('cfg-hourly').value = cfg.hourlyCap;
  $('cfg-daily').value = cfg.dailyCap;
  $('cfg-weekly').value = cfg.weeklyCap;
  $('cfg-burst').value = cfg.burstSize;
  $('cfg-coolH').value = cfg.perGroupCooldownHours;
  $('cfg-safeMode').checked = !!(await getSetting('safeMode', false));
  $('cfg-reuseTab').checked = !!(await getSetting('reusePublisherTab', true));
}

// ===== CSV Export =====
function toCSV(rows) {
  if (!rows?.length) return '';
  // Collect every key seen across all rows
  const cols = Array.from(rows.reduce((set, r) => {
    Object.keys(r).forEach((k) => set.add(k));
    return set;
  }, new Set()));
  const escape = (v) => {
    if (v == null) return '';
    const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
    return /[,"\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
  };
  const header = cols.join(',');
  const lines = rows.map((r) => cols.map((c) => escape(r[c])).join(','));
  return [header, ...lines].join('\n');
}

function downloadCSV(filename, content) {
  // Prepend BOM so Excel renders Hebrew correctly
  const blob = new Blob(['﻿' + content], { type: 'text/csv;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

const ts = () => new Date().toISOString().slice(0, 16).replace(/[:T]/g, '-');

$('export-groups-btn').addEventListener('click', async () => {
  const rows = await Groups.list();
  const stripped = rows.map(({ blob, ...rest }) => rest);
  downloadCSV(`groups-${ts()}.csv`, toCSV(stripped));
  toast(`יוצא ${rows.length} קבוצות`, 'ok');
});

$('export-posts-btn').addEventListener('click', async () => {
  const rows = await Posts.list();
  downloadCSV(`posts-${ts()}.csv`, toCSV(rows));
  toast(`יוצא ${rows.length} פוסטים`, 'ok');
});

$('export-jobs-btn').addEventListener('click', async () => {
  const rows = await Jobs.list();
  downloadCSV(`jobs-${ts()}.csv`, toCSV(rows));
  toast(`יוצא ${rows.length} משימות`, 'ok');
});

$('export-metrics-btn').addEventListener('click', async () => {
  try {
    const { SYNC } = await import('../lib/config.js');
    const { getSession } = await import('../lib/auth.js');
    const { token } = await getSession();
    const res = await fetch(`${SYNC.endpoint}/metrics/top?limit=500`, {
      headers: { 'X-Session-Token': token },
    });
    const json = await res.json();
    if (!json.ok) { toast('שגיאה: ' + json.error, 'err'); return; }
    downloadCSV(`metrics-${ts()}.csv`, toCSV(json.top || []));
    toast(`יוצא ${json.top.length} שורות מטריקות`, 'ok');
  } catch (e) {
    toast(String(e), 'err');
  }
});

$('save-cfg-btn').addEventListener('click', async () => {
  const cfg = {
    interPostMeanSec: Math.max(60, Number($('cfg-meanMin').value) * 60),
    interPostStddevSec: Number($('cfg-stddev').value),
    activeHourStart: Number($('cfg-startH').value),
    activeHourEnd: Number($('cfg-endH').value),
    hourlyCap: Number($('cfg-hourly').value),
    dailyCap: Number($('cfg-daily').value),
    weeklyCap: Number($('cfg-weekly').value),
    burstSize: Number($('cfg-burst').value),
    perGroupCooldownHours: Number($('cfg-coolH').value),
  };
  await chrome.runtime.sendMessage({ type: 'SET_THROTTLE_CONFIG', payload: cfg });
  await setSetting('safeMode', $('cfg-safeMode').checked);
  await setSetting('reusePublisherTab', $('cfg-reuseTab').checked);
  await setSetting('aiAutoGenerate', $('ai-autogen-toggle').checked);
  await setSetting('aiSafetyCheck', $('ai-safety-toggle').checked);
  await setSetting('aiTargetPostCount', Number($('ai-target-count').value) || 8);
  await setSetting('autoJoinEnabled', $('auto-join-toggle').checked);
  await setSetting('aiJoinSafetyCheck', $('ai-join-safety-toggle').checked);
  await setSetting('autoJoinDailyCap', Math.max(1, Math.min(30, Number($('auto-join-daily-cap').value) || 8)));
  await setSetting('autoJoinWeeklyCap', Math.max(5, Math.min(100, Number($('auto-join-weekly-cap').value) || 35)));
  await setSetting('autoBumpEnabled', $('auto-bump-toggle').checked);
  await setSetting('autoBumpText', $('auto-bump-text').value.trim() || null);
  await setSetting('eveningRefreshEnabled', $('evening-refresh-toggle').checked);
  await setSetting('eveningRefreshHour', Number($('evening-refresh-hour').value) || 21);
  await setSetting('liFirstCommentEnabled', $('li-first-comment-toggle').checked);
  await setSetting('liFirstCommentText', $('li-first-comment-text').value.trim() || null);
  await setSetting('commentsEnabled', $('comments-enabled-toggle').checked);
  // LinkedIn growth pass — parse keywords textarea (one per line, trim, drop empties)
  await setSetting('liGrowthEnabled', $('li-growth-toggle').checked);
  const liKws = ($('li-growth-keywords').value || '')
    .split('\n').map(s => s.trim()).filter(s => s.length > 0).slice(0, 25);
  await setSetting('liGrowthKeywords', liKws);
  await setSetting('liGrowthMaxLikes', Math.max(1, Math.min(5, Number($('li-growth-max-likes').value) || 3)));
  await setSetting('liGrowthStartHour', Math.max(0, Math.min(23, Number($('li-growth-start-hour').value) || 9)));
  await setSetting('liGrowthEndHour', Math.max(0, Math.min(23, Number($('li-growth-end-hour').value) || 19)));
  await setSetting('liGrowthCommentEnabled', $('li-growth-comment-toggle').checked);
  await setSetting('liGrowthAiCommentEnabled', $('li-growth-ai-comment-toggle').checked);
  await setSetting('liGrowthCommentText', $('li-growth-comment-text').value.trim() || null);
  await setSetting('userExpertise', $('li-growth-user-expertise').value.trim() || null);
  // Twitter growth pass
  await setSetting('twGrowthEnabled', $('tw-growth-toggle').checked);
  const twKwsSave = ($('tw-growth-keywords').value || '')
    .split('\n').map(s => s.trim()).filter(s => s.length > 0).slice(0, 25);
  await setSetting('twGrowthKeywords', twKwsSave);
  await setSetting('twGrowthMaxLikes', Math.max(1, Math.min(8, Number($('tw-growth-max-likes').value) || 5)));
  await setSetting('twGrowthStartHour', Math.max(0, Math.min(23, Number($('tw-growth-start-hour').value) || 9)));
  await setSetting('twGrowthEndHour', Math.max(0, Math.min(23, Number($('tw-growth-end-hour').value) || 22)));
  // LinkedIn auto-reply
  await setSetting('liAutoReplyEnabled', $('li-auto-reply-toggle').checked);
  await setSetting('liSelfHandle', $('li-auto-reply-self-handle').value.trim() || null);
  toast('הגדרות נשמרו', 'ok');
  syncSoon();
  refreshSyncPill();
});

// ---- "Run now" buttons — let the user test each growth automation immediately ----
async function _wireRunNowBtn(btnId, resultId, messageType) {
  const btn = document.getElementById(btnId);
  if (!btn) return;
  btn.addEventListener('click', async () => {
    btn.disabled = true;
    const result = document.getElementById(resultId);
    if (result) result.textContent = '⏳ מריץ...';
    try {
      const r = await chrome.runtime.sendMessage({ type: messageType });
      if (result) {
        result.textContent = r?.ok
          ? '✅ הופעל. בדוק את לוג'
          : '❌ ' + (r?.error || 'נכשל');
      }
    } catch (e) {
      if (result) result.textContent = '❌ ' + String(e?.message || e);
    } finally {
      setTimeout(() => { btn.disabled = false; }, 3000);
    }
  });
}
_wireRunNowBtn('li-growth-run-now-btn', 'li-growth-run-result', 'RUN_LI_GROWTH_NOW');
_wireRunNowBtn('tw-growth-run-now-btn', 'tw-growth-run-result', 'RUN_TW_GROWTH_NOW');
_wireRunNowBtn('li-auto-reply-run-now-btn', 'li-auto-reply-run-result', 'RUN_LI_REPLY_NOW');

$('sync-test-btn').addEventListener('click', async () => {
  const r = await chrome.runtime.sendMessage({ type: 'SYNC_TEST' });
  $('sync-status').textContent = r?.ok ? '✅ חיבור תקין' : '❌ ' + (r?.error || `status ${r?.status}`);
});

$('sync-now-btn').addEventListener('click', async () => {
  $('sync-now-btn').disabled = true;
  const r = await chrome.runtime.sendMessage({ type: 'SYNC_NOW' });
  $('sync-now-btn').disabled = false;
  if (r?.result?.skipped) {
    $('sync-status').textContent = '⚠ לא מוגדר';
  } else {
    const totals = r?.result?.totals || {};
    const sum = Object.values(totals).reduce((s, n) => s + n, 0);
    $('sync-status').textContent = `✅ ${sum} רשומות סונכרנו`;
    refreshSyncPill();
  }
});

// ========== Helpers ==========

function mkBtn(label, onClick) {
  const b = document.createElement('button');
  b.textContent = label;
  b.addEventListener('click', onClick);
  return b;
}

function emptyState(emoji, title, hint) {
  const li = document.createElement('li');
  li.className = 'empty-state';
  li.innerHTML = `<span class="emoji">${emoji}</span><strong>${title}</strong><span class="muted">${hint}</span>`;
  return li;
}

function fmtTime(ts) {
  if (!ts) return '';
  return new Date(ts).toLocaleString('he-IL', { hour: '2-digit', minute: '2-digit', day: '2-digit', month: '2-digit' });
}

function escapeHtml(s) {
  return String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
}

function statusLabel(s) {
  return ({ draft: 'טיוטה', active: 'פעיל', paused: 'מושהה', done: 'הסתיים' })[s] || s;
}

let toastTimer;
function toast(text, kind = '', durationMs = 2500) {
  let t = $('toast');
  if (!t) {
    t = document.createElement('div');
    t.id = 'toast';
    t.style.cssText = 'position:fixed;bottom:12px;left:50%;transform:translateX(-50%);padding:10px 16px;border-radius:8px;background:#1c1e21;color:white;font-size:12px;z-index:1000;box-shadow:0 4px 12px rgba(0,0,0,.2);transition:opacity .2s;max-width:calc(100% - 40px);text-align:center;';
    document.body.appendChild(t);
  }
  t.textContent = text;
  t.style.background = kind === 'err' ? '#e41e3f' : kind === 'ok' ? '#31a24c' : '#1c1e21';
  t.style.opacity = '1';
  clearTimeout(toastTimer);
  toastTimer = setTimeout(() => { t.style.opacity = '0'; }, durationMs);
}

// Global click-flash so every button visibly responds, even on rapid clicks.
document.addEventListener('click', (e) => {
  const btn = e.target.closest('button');
  if (!btn || btn.disabled) return;
  btn.classList.remove('flash');
  // force reflow so the animation restarts
  void btn.offsetWidth;
  btn.classList.add('flash');
  setTimeout(() => btn.classList.remove('flash'), 400);
}, true);

// ===== Init =====
$('logout-btn')?.addEventListener('click', doLogout);
$('logout-all-btn')?.addEventListener('click', async () => {
  if (!confirm('להתנתק מכל המכשירים? כל הסשנים יבוטלו וכל המכשירים האחרים יחויבו להיכנס מחדש.')) return;
  await logoutEverywhere();
  showLoginScreen();
});
// ===== ADMIN PANEL =====
async function adminFetch(path, opts = {}) {
  const { token } = await getSession();
  if (!token) throw new Error('not authenticated');
  const res = await fetch(`${SYNC.endpoint}${path}`, {
    ...opts,
    headers: { 'X-Session-Token': token, 'Content-Type': 'application/json', ...(opts.headers || {}) },
  });
  return res.json();
}

async function loadAdminPanel() {
  if (!IS_ADMIN) { toast('גישה לאדמין בלבד', 'err'); return; }
  await Promise.all([loadAdminStats(), loadAdminUsers(), loadAdminSettings(), loadAdminFleet(), loadAdminCommands()]);
}

async function loadAdminFleet() {
  try {
    const json = await adminFetch('/admin/devices');
    const list = $('admin-fleet-list');
    list.innerHTML = '';
    if (!json.ok || !json.devices?.length) {
      list.innerHTML = '<li class="muted" style="padding:8px;">אין פלאגינים פעילים</li>';
      return;
    }
    for (const d of json.devices) {
      const li = document.createElement('li');
      li.style.cssText = 'padding:8px; border-bottom:1px solid var(--border); display:flex; justify-content:space-between; align-items:center; gap:8px;';
      const dot = d.online ? '🟢' : '⚪';
      const lastSeen = d.lastSeen ? `${Math.round((Date.now() - d.lastSeen)/1000)}s ago` : 'מעולם לא';
      const ver = d.version ? `v${d.version}` : '?';
      const role = d.role === 'admin' ? '🛡' : '';
      li.innerHTML = `<div style="flex:1; min-width:0;">
        ${dot} <strong>${escapeHtml(d.username)}</strong> ${role}
        <span class="muted" style="font-size:11px;"> · ${ver} · ${lastSeen}</span><br>
        <span class="muted" style="font-size:10px;">${escapeHtml((d.userAgent || '').slice(0, 60))}</span>
      </div>`;
      const btn = document.createElement('button');
      btn.textContent = '📡 פקודה';
      btn.disabled = !d.online;
      btn.addEventListener('click', async () => {
        const type = prompt(`שלח פקודה ל-${d.username}:\n\nPING, SYNC_NOW, RUN_TICK_NOW, PAUSE_ALL, RESUME_ALL, SHOW_TOAST, RELOAD_EXTENSION, COLLECT_DIAGNOSTICS`, 'PING');
        if (!type) return;
        let payload = null;
        if (type === 'SHOW_TOAST') {
          const msg = prompt('הודעה להצגה:');
          if (msg) payload = { message: msg };
        }
        const r = await adminFetch(`/admin/devices/${encodeURIComponent(d.username)}/command`, {
          method: 'POST', body: JSON.stringify({ type, payload }),
        });
        if (r.ok) { toast(`✅ פקודה ${type} נשלחה`, 'ok'); setTimeout(loadAdminCommands, 1500); }
        else toast(r.error || 'נכשל', 'err');
      });
      li.appendChild(btn);
      list.appendChild(li);
    }
  } catch (e) { console.warn(e); }
}

async function loadAdminCommands() {
  try {
    const json = await adminFetch('/devices/commands/history?limit=30');
    const list = $('admin-commands-list');
    list.innerHTML = '';
    if (!json.ok || !json.commands?.length) {
      list.innerHTML = '<li class="muted" style="padding:8px;">אין פקודות עדיין</li>';
      return;
    }
    for (const c of json.commands) {
      const li = document.createElement('li');
      li.style.cssText = 'padding:6px 8px; border-bottom:1px solid var(--border); font-size:12px;';
      const statusColor = { pending: '#999', delivered: '#3a6', completed: '#0a0', failed: '#c00' }[c.status] || '#888';
      const when = new Date(c.created_at).toLocaleString('he-IL');
      li.innerHTML = `<div>
        <strong>${escapeHtml(c.type)}</strong>
        <span style="color:${statusColor};">[${c.status}]</span>
        <span class="muted"> → ${escapeHtml(c.client_id)} · ${when}</span>
        ${c.error ? `<br><span style="color:#c00; font-size:11px;">${escapeHtml(c.error)}</span>` : ''}
      </div>`;
      list.appendChild(li);
    }
  } catch (e) { console.warn(e); }
}

$('admin-refresh-fleet-btn')?.addEventListener('click', () => { loadAdminFleet(); loadAdminCommands(); });

$('admin-broadcast-btn')?.addEventListener('click', async () => {
  const type = $('admin-broadcast-type').value;
  if (!type) { toast('בחר פקודה לשידור', 'err'); return; }
  let payload = null;
  if (type === 'SHOW_TOAST') {
    const msg = prompt('הודעה לשידור לכל המשתמשים:');
    if (!msg) return;
    payload = { message: msg };
  }
  if (!confirm(`לשדר פקודה ${type} לכל הפלאגינים הפעילים במערכת?`)) return;
  const r = await adminFetch('/admin/broadcast', { method: 'POST', body: JSON.stringify({ type, payload }) });
  if (r.ok) { toast(`✅ נשלח ל-${r.sent} פלאגינים`, 'ok'); setTimeout(loadAdminCommands, 1500); }
  else toast(r.error || 'נכשל', 'err');
});

async function loadAdminStats() {
  try {
    const json = await adminFetch('/admin/stats');
    if (!json.ok) return;
    const s = json.stats;
    $('admin-stat-users').textContent = s.users;
    $('admin-stat-posts').textContent = s.posts;
    $('admin-stat-jobs').textContent = s.completedJobs;
    $('admin-stat-contacts').textContent = s.contacts;
    $('admin-stat-outreach').textContent = s.outreachMessages;
    $('admin-stat-apikeys').textContent = s.activeApiKeys;
  } catch (e) { console.warn(e); }
}

async function loadAdminUsers() {
  try {
    const json = await adminFetch('/admin/users');
    const list = $('admin-users-list');
    list.innerHTML = '';
    if (!json.ok) return;
    for (const u of (json.users || [])) {
      const li = document.createElement('li');
      li.style.cssText = 'padding:8px; border-bottom:1px solid var(--border); display:flex; justify-content:space-between; align-items:center; gap:8px;';
      const lastLogin = u.last_login_at ? new Date(u.last_login_at).toLocaleString('he-IL') : 'אף פעם';
      const roleBadge = u.role === 'admin' ? '<span style="background:#ffc107; padding:2px 6px; border-radius:4px; font-size:11px;">🛡 אדמין</span>' : '<span style="background:#e0e0e0; padding:2px 6px; border-radius:4px; font-size:11px;">משתמש</span>';
      li.innerHTML = `<div style="flex:1; min-width:0;"><strong>${escapeHtml(u.username)}</strong> ${roleBadge}<br><span class="muted" style="font-size:11px;">כניסה אחרונה: ${lastLogin} · סשנים פעילים: ${u.active_sessions || 0}</span></div>`;
      const btn = document.createElement('button');
      btn.textContent = u.role === 'admin' ? '↓ הסר אדמין' : '↑ הפוך לאדמין';
      btn.addEventListener('click', async () => {
        const newRole = u.role === 'admin' ? 'user' : 'admin';
        if (!confirm(`לשנות את ${u.username} ל-${newRole === 'admin' ? 'אדמין' : 'משתמש רגיל'}?`)) return;
        const r = await adminFetch('/admin/users/role', { method: 'POST', body: JSON.stringify({ username: u.username, role: newRole }) });
        if (r.ok) { toast('עודכן', 'ok'); loadAdminUsers(); }
        else toast(r.error || 'נכשל', 'err');
      });
      li.appendChild(btn);
      list.appendChild(li);
    }
  } catch (e) { console.warn(e); }
}

async function loadAdminSettings() {
  try {
    const json = await adminFetch('/admin/settings');
    if (!json.ok) return;
    const s = json.settings || {};
    const v = (k, d) => s[k]?.value ?? d;
    $('admin-set-maintenance').value = String(v('maintenanceMode', false));
    $('admin-set-max-batch').value = v('maxBatchSize', 500);
    $('admin-set-global-rate').value = v('globalRateLimitPerHour', 0);
    $('admin-set-banner').value = v('systemBanner', '');
    $('admin-set-daily-cap').value = v('newUserDailyCap', 0);
    const platforms = v('enabledPlatforms', { facebook: true, linkedin: true, twitter: true, reddit: true, instagram: true });
    $('admin-plat-facebook').checked = !!platforms.facebook;
    $('admin-plat-linkedin').checked = !!platforms.linkedin;
    $('admin-plat-twitter').checked = !!platforms.twitter;
    $('admin-plat-reddit').checked = !!platforms.reddit;
    $('admin-plat-instagram').checked = !!platforms.instagram;
    $('admin-set-allow-signup').checked = !!v('allowSignup', false);
    $('admin-set-force-gemini').checked = !!v('forceGeminiKey', false);
    // Show last-saved info
    const lastKey = Object.values(s).sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0))[0];
    if (lastKey) {
      $('admin-last-saved').textContent = `עודכן לאחרונה ב-${new Date(lastKey.updatedAt).toLocaleString('he-IL')} ע"י ${lastKey.updatedBy}`;
    }
  } catch (e) { console.warn(e); }
}

$('admin-refresh-stats-btn')?.addEventListener('click', loadAdminStats);
$('admin-reload-settings-btn')?.addEventListener('click', loadAdminSettings);

$('admin-save-settings-btn')?.addEventListener('click', async () => {
  const payload = {
    maintenanceMode: $('admin-set-maintenance').value === 'true',
    maxBatchSize: Number($('admin-set-max-batch').value) || 500,
    globalRateLimitPerHour: Number($('admin-set-global-rate').value) || 0,
    systemBanner: $('admin-set-banner').value.trim(),
    newUserDailyCap: Number($('admin-set-daily-cap').value) || 0,
    enabledPlatforms: {
      facebook: $('admin-plat-facebook').checked,
      linkedin: $('admin-plat-linkedin').checked,
      twitter: $('admin-plat-twitter').checked,
      reddit: $('admin-plat-reddit').checked,
      instagram: $('admin-plat-instagram').checked,
    },
    allowSignup: $('admin-set-allow-signup').checked,
    forceGeminiKey: $('admin-set-force-gemini').checked,
  };
  try {
    const btn = $('admin-save-settings-btn');
    btn.disabled = true; btn.classList.add('busy');
    const r = await adminFetch('/admin/settings', { method: 'POST', body: JSON.stringify(payload) });
    btn.disabled = false; btn.classList.remove('busy');
    if (r.ok) { toast(`✅ נשמרו ${r.count} הגדרות`, 'ok'); loadAdminSettings(); }
    else toast(r.error || 'שמירה נכשלה', 'err');
  } catch (e) { toast('שגיאה: ' + e.message, 'err'); }
});

// Listen for remote SHOW_TOAST commands forwarded by service-worker
chrome.runtime.onMessage.addListener((msg) => {
  if (msg?.type === 'SHOW_TOAST' && msg.message) {
    toast(msg.message, msg.level || 'info', 5000);
  }
  // Live agent-activity feed — prepend whatever the background agent just did.
  if (msg?.type === 'AGENT_ACTIVITY' && msg.entry) {
    try { prependActivity(msg.entry); } catch {}
  }
});

bootstrap();

// ============== AI MODE — guided autopilot ==============
// State machine:
//   no-profile          → wizard (5 questions) → /brand-profile POST
//   profile, inactive   → "Activate (DRY RUN)" / "Activate LIVE" buttons
//   active, onboarding  → next step button
//   active, content_review → analysis preview + approval ui
// At ANY active state, Stop button kills the run via /ai-mode/stop.
// All Worker calls go through the active run row — Sprint 3+ will use the
// same state machine, just adding more `current_step` values.
async function aiModeInit() {
  const statusEl   = document.getElementById('ai-mode-status');
  const startBtn   = document.getElementById('ai-mode-start-btn');
  const stopBtn    = document.getElementById('ai-mode-stop-btn');
  const editBtn    = document.getElementById('ai-mode-edit-profile-btn');
  const wizard     = document.getElementById('ai-mode-wizard');
  const modeBadge  = document.getElementById('ai-mode-mode-badge');
  const inactiveControls = document.getElementById('ai-mode-inactive-controls');
  const activeControls   = document.getElementById('ai-mode-active-controls');
  const stepActions      = document.getElementById('ai-mode-step-actions');
  const analysisPreview  = document.getElementById('ai-mode-analysis-preview');
  if (!statusEl || !startBtn) return;

  let cachedProfile = null;
  let cachedRun = null;

  async function api(path, init = {}) {
    const { token } = await getSession();
    return fetch(`${SYNC.endpoint}/api/v1/${path}`, {
      ...init,
      headers: { 'Content-Type': 'application/json', 'X-Session-Token': token, ...(init.headers || {}) },
    }).then(r => r.json());
  }

  async function refresh() {
    statusEl.textContent = '⏳ בודק מצב...';
    analysisPreview.innerHTML = '';
    try {
      const [profileR, stateR] = await Promise.all([
        api('ai-mode/brand-profile'),
        api('ai-mode/state'),
      ]);
      cachedProfile = profileR.configured ? profileR.profile : null;
      cachedRun = stateR.active ? stateR.run : null;
      render();
      // Restore any in-flight / recently-finished scan progress (survives reopen).
      try { renderScanProgress(await getSetting('aiScanState', {})); } catch {}
      // Show her actual scanned posts so she can review how she publishes (ADR-34).
      try { await showScannedPosts(); } catch {}
    } catch (e) {
      statusEl.textContent = '❌ ' + String(e?.message || e);
    }
  }

  // Fetch + render the user's REAL scanned posts (historical snapshots) so the
  // plugin surface — not only the dashboard — lets her review how she publishes.
  async function showScannedPosts() {
    const r = await api('ai-mode/history-snapshots').catch(() => ({ snapshots: [] }));
    const snaps = r.snapshots || [];
    if (!snaps.length) return;
    const esc = (s) => String(s || '').replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
    const rows = snaps.slice(0, 20).map(s => `
      <div style="padding:8px 10px;background:rgba(0,0,0,.15);border-radius:8px;margin-bottom:6px;">
        <div style="white-space:pre-wrap;font-size:12px;line-height:1.45;">${esc((s.post_text || '(ללא טקסט)').slice(0, 280))}${(s.post_text || '').length > 280 ? '…' : ''}</div>
        <div style="margin-top:4px;font-size:11px;opacity:.7;">👍 ${s.likes ?? 0} · 💬 ${s.comments ?? 0} · ↗ ${s.shares ?? 0}${s.image_count ? ` · 🖼 ${s.image_count}` : ''}</div>
      </div>`).join('');
    analysisPreview.innerHTML += `
      <details style="margin-top:12px;">
        <summary style="cursor:pointer;font-weight:600;font-size:13px;">📝 הפוסטים שלך שנסרקו (${snaps.length}) — ככה אתה מפרסם</summary>
        <div style="margin-top:8px;max-height:340px;overflow:auto;">${rows}${snaps.length > 20 ? `<p style="font-size:11px;opacity:.7;">מוצגים 20 מתוך ${snaps.length}. הכל בדשבורד.</p>` : ''}</div>
      </details>`;
  }

  function render() {
    if (cachedRun) {
      // ── ACTIVE ──
      inactiveControls.hidden = true;
      activeControls.hidden = false;
      modeBadge.style.display = '';
      const dry = !!cachedRun.dry_run;
      modeBadge.textContent = dry ? '🧪 DRY RUN' : '🔴 LIVE';
      modeBadge.style.background = dry ? '#fbbf24' : '#dc2626';
      modeBadge.style.color = '#fff';
      const goalLabel = { leads:'לידים', brand:'מותג', shares:'שיתופים', education:'חינוך', mixed:'תמהיל' }[cachedProfile?.goal] || '';
      statusEl.innerHTML = `
        <strong>📊 שלב ${cachedRun.current_step} · ${stepName(cachedRun.status)}</strong><br>
        ${cachedProfile ? `🎯 ${escapeHtml(goalLabel)} · 🎤 ${escapeHtml(cachedProfile.tone)}` : ''}
      `;
      renderStepActions();
    } else {
      // ── INACTIVE ──
      inactiveControls.hidden = false;
      activeControls.hidden = true;
      modeBadge.style.display = 'none';
      stepActions.innerHTML = '';
      if (cachedProfile) {
        const goalLabel = { leads:'לידים', brand:'מותג', shares:'שיתופים', education:'חינוך', mixed:'תמהיל' }[cachedProfile.goal] || cachedProfile.goal;
        statusEl.innerHTML = `
          ✓ פרופיל קיים: <strong>${escapeHtml((cachedProfile.business_description || '').slice(0, 60))}…</strong><br>
          🎯 ${escapeHtml(goalLabel)} · 🎤 ${escapeHtml(cachedProfile.tone)} · 👥 ${escapeHtml((cachedProfile.audience || '').slice(0, 40))}
        `;
        editBtn.hidden = false;
        startBtn.textContent = '🧪 הפעל מצב AI (DRY RUN)';
      } else {
        statusEl.textContent = 'לא הגדרת פרופיל. לחץ "התחל" כדי לתת ל-Gemini להבין את העסק שלך.';
        editBtn.hidden = true;
        startBtn.textContent = '🤖 התחל';
      }
    }
  }

  function stepName(status) {
    return ({
      onboarding: 'היכרות',
      analyzing_history: 'מנתח היסטוריה',
      content_review: 'אישור תוכן',
      group_scoring: 'דירוג קבוצות',
      scheduling: 'בניית לוז',
      active: 'מפרסם',
    })[status] || status || '?';
  }

  function renderStepActions() {
    stepActions.innerHTML = '';
    analysisPreview.innerHTML = '';
    if (!cachedRun) return;
    const mkBtn = (label, handler, klass = 'primary') => {
      const b = document.createElement('button');
      b.className = klass; b.textContent = label;
      b.addEventListener('click', handler);
      return b;
    };
    if (cachedRun.status === 'onboarding') {
      stepActions.appendChild(mkBtn('🔍 שלב 2 — סרוק טיימליין', () => runHistoryScan()));
      stepActions.appendChild(mkBtn('🎯 סרוק את הפוסטים שלי בקבוצות', () => runGroupScan(), 'primary'));
      stepActions.appendChild(mkBtn('🤖 אוטופיילוט — הכן תוכנית מלאה (DRY RUN)', () => runAutopilot(), 'primary'));
    } else if (cachedRun.status === 'content_review') {
      stepActions.appendChild(mkBtn('✨ שלב 3 — צור 20 פוסטים על בסיס הניתוח', runGenerateContent));
      previewLastAction('analyze');
    } else if (cachedRun.status === 'group_scoring') {
      stepActions.appendChild(mkBtn('👥 שלב 4 — דרג את הקבוצות שלי', runScoreGroups));
      previewLastAction('create_post');
    } else if (cachedRun.status === 'scheduling') {
      stepActions.appendChild(mkBtn('📅 שלב 5 — בנה לוז פרסום (14 ימים)', runBuildSchedule));
      previewLastAction('score_group');
    } else if (cachedRun.status === 'active') {
      previewLastAction('schedule');
      analysisPreview.innerHTML += `
        <div style="margin-top:10px; padding:10px; background:rgba(46,204,113,0.15); border-radius:6px;">
          <strong>🎉 הזרימה הסתיימה</strong><br>
          ${cachedRun.dry_run ? '🧪 כל הנתונים נשמרו במצב DRY RUN — שום דבר לא פורסם. בדוק בדשבורד.' : '🔴 LIVE — הלוז יתחיל לפעול ב-9:00 מחר.'}
        </div>
      `;
    }
    // Autonomous master switch (ADR-39) — one tap and the agent works on its own.
    const autoOn = mkBtn('🤖 הפעל מצב אוטונומי (עובד לבד)', () => setAutonomous(true, false), 'primary');
    autoOn.style.cssText = 'width:100%;background:#10b981;border-color:#10b981;font-weight:700;margin-bottom:6px;';
    stepActions.appendChild(autoOn);
    const autoOff = mkBtn('🔴 כבה מצב אוטונומי', () => setAutonomous(false, false), '');
    autoOff.style.cssText = 'font-size:12px;padding:5px 12px;opacity:.85;margin-bottom:6px;';
    stepActions.appendChild(autoOff);

    // The unified agent cycle (ADR-35) — always available: runs the whole loop
    // in one shot (sync groups → analyze → discover → generate → schedule).
    const agentBtn = mkBtn('🚀 הפעל סוכן מלא — מחזור אחד', () => runAgentCycle(), 'primary');
    agentBtn.style.cssText = 'width:100%;background:linear-gradient(90deg,#10b981,#059669);border-color:#059669;font-weight:700;margin-bottom:6px;';
    stepActions.appendChild(agentBtn);

    // Always offer a clean restart — a run can get stuck at any step, and the
    // user needs a way out that doesn't depend on the current status.
    const resetBtn = mkBtn('🔄 התחל תהליך AI מחדש', () => resetAiMode(), '');
    resetBtn.style.cssText = 'font-size:12px;padding:5px 12px;opacity:.85;';
    stepActions.appendChild(resetBtn);
  }

  // Autonomous master switch (ADR-39). One tap → the agent works on its own each
  // hour (generate/schedule/maintain), consistent + human-like. DRY RUN default.
  async function setAutonomous(enabled, live) {
    if (enabled && live && !confirm('⚡ מצב LIVE — הסוכן יפרסם פוסטים אמיתיים בקצב אנושי. להפעיל?')) return;
    if (enabled && !confirm('🤖 להפעיל מצב אוטונומי? הסוכן יעבוד לבד כל שעה — ייצור תוכן, יתזמן ויתחזק. אתה רק תאשר טיוטות ותקבל דוח יומי.')) return;
    try {
      const r = await chrome.runtime.sendMessage({ type: 'AI_AUTONOMOUS_SET', payload: { enabled, live } });
      if (r?.ok) toast(enabled ? `🟢 מצב אוטונומי פעיל (${live ? 'LIVE' : 'DRY RUN'}) — עובד לבד` : '🔴 מצב אוטונומי כובה', 'ok', 4000);
      else toast('❌ ' + (r?.error || 'שגיאה'), 'err', 6000);
    } catch (e) { toast('❌ ' + String(e?.message || e), 'err', 6000); }
    refresh();
  }

  // The unified agent cycle (ADR-35) — one button, the whole loop. DRY RUN.
  async function runAgentCycle() {
    if (!confirm('🚀 הסוכן יריץ מחזור מלא: יסנכרן את הקבוצות שלך → ינתח את הזהות והסגנון שלך → יגלה קבוצות חדשות רלוונטיות → ייצר תוכן בסגנונך → יבנה לוז.\n\nהכל ב-DRY RUN — שום דבר לא יפורסם. דורש טאב פייסבוק פתוח ומחובר. אפשר לסגור את החלון — זה ימשיך ברקע.\n\nלהתחיל?')) return;
    obLog.event('ai_agent_cycle_click');
    await setScanProgressLocal({ running: true, phase: 'starting', pct: 3, message: '🤖 הסוכן מתחיל מחזור מלא…', error: null, result: null, footprint: [], groupPosts: [], mode: 'agent' });
    try { chrome.runtime.sendMessage({ type: 'AI_AGENT_CYCLE_START', payload: {} }); }
    catch (e) { toast('❌ ' + String(e?.message || e), 'err', 6000); }
  }

  // Full reset — clean restart from scratch (local + server). The SW clears the
  // hidden AI-Mode campaign/jobs + scan memory and calls the server reset
  // (abandon run + purge posts/scores/schedule). Brand profile is kept.
  async function resetAiMode() {
    if (!confirm('🔄 לאפס את כל תהליך ה-AI ולהתחיל מחדש?\n\nיימחקו: הפוסטים שנוצרו, דירוגי הקבוצות, והלוז (מקומי + שרת). פרופיל המותג יישמר.\n\nלהמשיך?')) return;
    obLog.event('ai_mode_full_reset_click');
    await setScanProgressLocal({ running: true, phase: 'resetting', pct: 15, message: '🔄 מאפס תהליך AI…', error: null, mode: 'reset' });
    try {
      chrome.runtime.sendMessage({ type: 'AI_MODE_FULL_RESET', payload: { purge: true } });
      toast('🔄 מאפס… ימשיך ברקע. פתח מחדש להתחלה נקייה.', 'ok', 4000);
    } catch (e) {
      toast('❌ ' + String(e?.message || e), 'err', 6000);
    }
  }

  async function previewLastAction(kind) {
    try {
      const r = await api('ai-mode/actions');
      const action = (r.actions || []).find(a => a.kind === kind);
      if (action) {
        analysisPreview.innerHTML = `
          <div style="margin-top:10px; padding:10px; background:rgba(46,204,113,0.1); border-radius:6px;">
            ✓ ${escapeHtml(action.summary)}
          </div>
        ` + analysisPreview.innerHTML;
      }
    } catch {}
  }

  async function runGenerateContent() {
    if (!confirm(cachedRun?.dry_run
      ? '✨ Gemini ייצר 20 פוסטים מותאמים אישית. אורך ~30 שניות. במצב DRY RUN — לא מתפרסמים. להמשיך?'
      : '🔴 LIVE — להמשיך?')) return;
    statusEl.textContent = '⏳ Gemini יוצר פוסטים... זה לוקח 20-40 שניות.';
    const r = await chrome.runtime.sendMessage({ type: 'AI_MODE_GENERATE_CONTENT', payload: { count: 20 } });
    if (r?.ok) {
      toast(`✅ נוצרו ${r.generated} פוסטים`, 'ok', 6000);
      refresh();
    } else {
      toast('❌ ' + (r?.error || 'שגיאה'), 'err', 6000);
      statusEl.textContent = '❌ ' + (r?.error || 'שגיאה');
    }
  }

  async function runScoreGroups() {
    if (!confirm(cachedRun?.dry_run
      ? '👥 ייפתח מסך הקבוצות שלך, ייסרק ויעבור ל-Gemini לדירוג. שום דבר לא יפורסם. להמשיך?'
      : '🔴 LIVE — להמשיך?')) return;
    statusEl.textContent = '⏳ פותח את רשימת הקבוצות וסורק...';
    const r = await chrome.runtime.sendMessage({ type: 'AI_MODE_SCORE_GROUPS', payload: {} });
    if (r?.ok) {
      toast(`✅ דורגו ${r.scored} קבוצות`, 'ok', 6000);
      refresh();
    } else {
      toast('❌ ' + (r?.error || 'שגיאה'), 'err', 6000);
      statusEl.textContent = '❌ ' + (r?.error || 'שגיאה');
    }
  }

  async function runBuildSchedule() {
    const days = parseInt(prompt('כמה ימים קדימה לבנות את הלוז?', '14') || '14', 10);
    if (!days || days < 1) return;
    statusEl.textContent = '⏳ בונה לוז פרסום...';
    const r = await chrome.runtime.sendMessage({ type: 'AI_MODE_BUILD_SCHEDULE', payload: { days, minScore: 7 } });
    if (r?.ok) {
      toast(`✅ ${r.scheduled} פרסומים תוכננו ל-${days} ימים`, 'ok', 6000);
      refresh();
    } else {
      toast('❌ ' + (r?.error || 'שגיאה'), 'err', 6000);
      statusEl.textContent = '❌ ' + (r?.error || 'שגיאה');
    }
  }

  // Render the scan progress card from the persisted aiScanState. Because the
  // scan runs in the service worker and writes progress to storage, this shows
  // correctly even if the popup was closed during the scan and reopened.
  function renderScanProgress(st) {
    if (!st || (!st.running && st.phase !== 'done' && st.phase !== 'error')) return false;
    const pct = Math.max(0, Math.min(100, Number(st.pct) || 0));
    const barColor = st.phase === 'error' ? '#dc2626' : (st.phase === 'done' ? '#16a34a' : '#2563eb');
    const fp = Array.isArray(st.footprint) ? st.footprint : [];
    const gp = Array.isArray(st.groupPosts) ? st.groupPosts : [];
    const c  = st.counts || {};
    const shots = Array.isArray(st.screenshots) ? st.screenshots : [];
    const concl = Array.isArray(st.conclusions) ? st.conclusions : [];
    // Live screenshots of the browser while it scanned ("watch it work").
    const shotsHtml = shots.length ? `
      <div style="margin-top:10px;">
        <strong style="font-size:12px;">📸 צילומי הסריקה (${shots.length})</strong>
        <div id="scan-shots" style="display:flex;gap:6px;overflow-x:auto;margin-top:4px;padding-bottom:4px;">
          ${shots.map(s => `<a href="${s.dataUrl}" target="_blank" title="${escapeHtml(s.label||'')}" style="flex:0 0 auto;">
            <img src="${s.dataUrl}" style="height:90px;border-radius:6px;border:1px solid var(--border,#ccc);display:block;"></a>`).join('')}
        </div>
      </div>` : '';
    // Per-scan conclusions.
    const conclHtml = concl.length ? `
      <div style="margin-top:10px;padding:8px;background:rgba(16,185,129,0.08);border:1px solid rgba(16,185,129,0.25);border-radius:8px;font-size:12px;">
        <strong>🧠 מסקנות הסריקה:</strong>
        <ul style="margin:4px 0 0;padding-inline-start:18px;line-height:1.6;">
          ${concl.map(x => `<li>${escapeHtml(x)}</li>`).join('')}
        </ul>
      </div>` : '';
    // Groups she publishes in (the footprint) — proven publishing targets.
    const fpHtml = fp.length ? `
      <div style="margin-top:10px;font-size:12px;">
        <strong>📍 קבוצות שאתה מפרסם בהן${st.imported ? ` — ${st.imported} יובאו כיעדים` : ''}:</strong>
        ${fp.slice(0, 12).map(g => `<div class="row" style="justify-content:space-between;gap:6px;margin-top:2px;">
          <span style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${escapeHtml(g.name || g.fb_group_id)}</span>
          <span class="muted" style="white-space:nowrap;">${g.post_count} פוסטים · 👍${g.likes || 0} 💬${g.comments || 0}</span></div>`).join('')}
      </div>` : '';
    // The ACTUAL posts found in groups — real results, not just a summary.
    const gpHtml = gp.length ? `
      <details style="margin-top:10px;font-size:12px;" open>
        <summary style="cursor:pointer;font-weight:600;">📝 הפוסטים שנמצאו בקבוצות (${gp.length})</summary>
        <div style="max-height:220px;overflow:auto;margin-top:4px;">
          ${gp.map(p => `<div style="padding:6px;border:1px solid var(--border,#e5e7eb);border-radius:6px;margin-top:4px;">
            <div class="muted" style="font-size:11px;">📍 ${escapeHtml(p.group_name || p.group_id)} · 👍${p.likes} 💬${p.comments} ↗${p.shares}</div>
            <div style="margin-top:2px;">${escapeHtml(p.text || '(ללא טקסט)')}</div>
          </div>`).join('')}
        </div>
      </details>` : '';
    // Honest note when the timeline exposed no group posts.
    const noteHtml = (!st.running && !fp.length && st.phase !== 'error') ? `
      <div class="muted" style="margin-top:8px;font-size:11px;line-height:1.5;">
        לא נמצאו פוסטים <strong>בקבוצות</strong> בטיימליין${c.wall ? ` (רק ${c.wall} פוסטי-וול/חברים — סוננו)` : ''}.
        פייסבוק לא תמיד מציג פוסטי-קבוצות בטיימליין האישי. לכיסוי מלא נדרשת סריקת קבוצה-אחר-קבוצה (בפיתוח).
        אפשר להעמיק את הסריקה עם הכפתור למטה.
      </div>` : '';
    const countsHtml = (c.total != null)
      ? `<span class="muted" style="font-size:11px;"> · ${c.group || 0} חדש בקבוצות${c.skipped ? ` · ${c.skipped} דילוג` : ''}</span>`
      : '';
    analysisPreview.innerHTML = `
      <div style="margin-top:10px;padding:10px;background:rgba(37,99,235,0.06);border:1px solid rgba(37,99,235,0.2);border-radius:8px;">
        <div class="row" style="justify-content:space-between;">
          <strong style="font-size:13px;">${st.phase === 'error' ? '❌ שגיאת סריקה' : (st.phase === 'done' ? '✅ הסריקה הושלמה' : '⏳ סורק פוסטים בקבוצות…')}${countsHtml}</strong>
          <span class="muted" style="font-size:11px;">${pct}%</span>
        </div>
        <div style="height:6px;background:rgba(0,0,0,0.08);border-radius:3px;margin:6px 0;overflow:hidden;">
          <div style="height:100%;width:${pct}%;background:${barColor};transition:width .3s;"></div>
        </div>
        <div class="muted" style="font-size:12px;">${escapeHtml(st.error || st.message || '')}</div>
        ${shotsHtml}
        ${conclHtml}
        ${fpHtml}
        ${gpHtml}
        ${noteHtml}
        ${!st.running ? `<div class="row" style="gap:6px;margin-top:8px;flex-wrap:wrap;">
          <button id="ai-scan-deeper" class="btn" style="font-size:12px;padding:4px 10px;">🔍 סרוק עוד (חדש בלבד)</button>
          <button id="ai-scan-reset" class="btn" style="font-size:12px;padding:4px 10px;" title="ניקוי הזיכרון — סריקה מחדש מאפס">♻ אפס זיכרון</button>
          <button id="ai-scan-dismiss" class="btn" style="font-size:12px;padding:4px 10px;">סגור</button>
        </div>` : ''}
      </div>`;
    const dismiss = document.getElementById('ai-scan-dismiss');
    if (dismiss) dismiss.addEventListener('click', async () => { await setSetting('aiScanState', {}); analysisPreview.innerHTML = ''; refresh(); });
    const deeper = document.getElementById('ai-scan-deeper');
    // "Scan more" keeps memory (skips known posts); a modest depth bump, still low-exposure.
    if (deeper) deeper.addEventListener('click', () => runHistoryScan({ maxPosts: 25, maxScrolls: 12 }));
    const reset = document.getElementById('ai-scan-reset');
    if (reset) reset.addEventListener('click', async () => {
      if (!confirm('לאפס את זיכרון הסריקה? הסריקה הבאה תתחיל מאפס (יותר חשיפה).')) return;
      try { await chrome.runtime.sendMessage({ type: 'AI_MODE_RESET_SCAN_MEMORY' }); } catch {}
      analysisPreview.innerHTML = ''; toast('♻ זיכרון הסריקה אופס', 'ok', 4000); refresh();
    });
    return true;
  }

  // Non-blocking: fire the scan and let progress flow through storage + pushes.
  // The scan keeps running in the service worker even if this popup is closed.
  async function runHistoryScan(opts = {}) {
    if (!confirm(cachedRun?.dry_run
      ? '🧪 מסך FB ייפתח ברקע, יסרוק את הפוסטים שאתה מפרסם בקבוצות (החוצה), וינתח דרך AI. אף פעולה לא תפורסם. אפשר לסגור את החלון — הסריקה תמשיך ברקע. להמשיך?'
      : '🔴 מצב LIVE. הסקירה תרוץ ברקע. להמשיך?')) return;
    obLog.event('ai_mode_history_scan_click');
    const maxPosts = Number(opts.maxPosts) || 15;   // minimum exposure by default
    const maxScrolls = Number(opts.maxScrolls) || 6;
    await setScanProgressLocal({ running: true, phase: 'starting', pct: 3, message: 'מתחיל…', error: null, result: null, footprint: [], groupPosts: [] });
    try {
      chrome.runtime.sendMessage({ type: 'AI_MODE_SCAN_HISTORY', payload: { maxPosts, maxScrolls } });
    } catch (e) {
      toast('❌ ' + String(e?.message || e), 'err', 6000);
    }
  }

  // Autopilot (DRY RUN) — plan everything; nothing publishes.
  async function runAutopilot() {
    if (!confirm('🤖 האוטופיילוט יכין תוכנית מלאה: פוסטים + דירוג קבוצות + לוז — הכל ב-DRY RUN, שום דבר לא יפורסם. אפשר לסגור את החלון — זה ימשיך ברקע. להמשיך?')) return;
    obLog.event('ai_mode_autopilot_click');
    await setScanProgressLocal({ running: true, phase: 'starting', pct: 4, message: '🤖 אוטופיילוט מתחיל…', error: null, result: null, footprint: [], groupPosts: [], mode: 'autopilot' });
    try { chrome.runtime.sendMessage({ type: 'AI_AUTOPILOT_START', payload: {} }); }
    catch (e) { toast('❌ ' + String(e?.message || e), 'err', 6000); }
  }

  // Phase B — scan her actual posts inside a few of her groups (min exposure).
  async function runGroupScan(opts = {}) {
    if (!confirm('🎯 ייפתחו כמה מהקבוצות שלך (3 בכל פעם) לסריקת הפוסטים שאתה מפרסם שם. חשיפה מינימלית — קבוצות שכבר נסרקו לא נבדקות שוב. להמשיך?')) return;
    obLog.event('ai_mode_group_scan_click');
    await setScanProgressLocal({ running: true, phase: 'starting', pct: 3, message: 'מתחיל סריקת קבוצות…', error: null, result: null, footprint: [], groupPosts: [], mode: 'groups' });
    try {
      chrome.runtime.sendMessage({ type: 'AI_MODE_SCAN_GROUPS', payload: { maxGroups: Number(opts.maxGroups) || 3, perGroup: 10 } });
    } catch (e) {
      toast('❌ ' + String(e?.message || e), 'err', 6000);
    }
  }

  // Optimistic local write so the bar shows instantly before the SW's first push.
  async function setScanProgressLocal(patch) {
    let st = {};
    try { st = (await getSetting('aiScanState', {})) || {}; } catch {}
    const next = { ...st, ...patch, updatedAt: Date.now() };
    try { await setSetting('aiScanState', next); } catch {}
    renderScanProgress(next);
  }

  // ── Start / activate ──
  startBtn.addEventListener('click', async () => {
    if (!cachedProfile) {
      obLog.event('ai_mode_wizard_opened');
      openWizard();
      return;
    }
    // Profile exists — activate in DRY RUN by default
    obLog.event('ai_mode_activate_dryrun');
    statusEl.textContent = '⏳ מפעיל מצב AI (DRY RUN)...';
    const r = await api('ai-mode/activate', { method: 'POST', body: JSON.stringify({ dry_run: true }) });
    if (r.ok) {
      toast('🧪 מצב AI פעיל ב-DRY RUN. שום דבר לא יפורסם.', 'ok', 5000);
      refresh();
    } else {
      toast('❌ ' + (r.error || 'הפעלה נכשלה'), 'err', 6000);
    }
  });

  stopBtn?.addEventListener('click', async () => {
    if (!confirm('🛑 לעצור את מצב ה-AI? כל פעולה אוטומטית תיפסק. אפשר להפעיל מחדש אחר כך.')) return;
    obLog.event('ai_mode_stop_clicked');
    const r = await api('ai-mode/stop', { method: 'POST', body: JSON.stringify({ reason: 'user_stopped' }) });
    if (r.ok) {
      toast('🛑 מצב AI נעצר.', 'ok', 4000);
      refresh();
    } else {
      toast('❌ ' + (r.error || 'עצירה נכשלה'), 'err', 4000);
    }
  });

  function openWizard(prefill = null) {
    wizard.hidden = false;
    if (prefill) {
      $('bp-business').value     = prefill.business_description || '';
      $('bp-audience').value     = prefill.audience || '';
      $('bp-goal').value         = prefill.goal || 'leads';
      $('bp-tone').value         = prefill.tone || 'professional';
      $('bp-competitors').value  = prefill.competitors || '';
    }
    wizard.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }
  editBtn?.addEventListener('click', () => openWizard(cachedProfile));
  $('bp-cancel-btn').addEventListener('click', () => { wizard.hidden = true; });

  // ── Web Speech API — dictation for textareas ──
  // SpeechRecognition lives on the page-window, not the extension SW.
  // Hebrew lang = 'he-IL'; falls back gracefully if not supported.
  const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
  let activeReco = null;
  document.querySelectorAll('.speech-btn').forEach(btn => {
    btn.addEventListener('click', async () => {
      const targetId = btn.dataset.speechTarget;
      const ta = document.getElementById(targetId);
      if (!SR) { toast('הדפדפן לא תומך בהכתבה קולית', 'err', 3000); return; }
      if (activeReco) { try { activeReco.stop(); } catch {} activeReco = null; btn.textContent = '🎤'; return; }
      try {
        const r = new SR();
        r.lang = 'he-IL';
        r.interimResults = true;
        r.continuous = true;
        const baseValue = ta.value;
        r.onresult = (ev) => {
          let finalText = '', interim = '';
          for (let i = ev.resultIndex; i < ev.results.length; i++) {
            const t = ev.results[i][0].transcript;
            if (ev.results[i].isFinal) finalText += t;
            else interim += t;
          }
          ta.value = (baseValue + ' ' + finalText + interim).trim();
        };
        r.onerror = (ev) => {
          toast('שגיאת מיקרופון: ' + ev.error, 'err', 4000);
          btn.textContent = '🎤';
          activeReco = null;
        };
        r.onend = () => {
          btn.textContent = '🎤';
          activeReco = null;
        };
        r.start();
        activeReco = r;
        btn.textContent = '⏹';
      } catch (e) {
        toast('לא הצלחתי להפעיל הקלטה: ' + String(e?.message || e), 'err', 4000);
      }
    });
  });

  // ── Provider chip: which AI runs the brand profile? ──
  (async () => {
    const chip = $('bp-provider-chip');
    if (!chip) return;
    try {
      const [providers, trial] = await Promise.all([
        api('ai/providers').catch(() => ({ providers: [] })),
        api('ai/trial').catch(() => ({ initialized: false })),
      ]);
      const def = (providers.providers || []).find(p => p.is_default && p.is_active);
      if (def) {
        chip.innerHTML = `🧠 הסוכן ירוץ על: <strong>${escapeHtml(def.label || def.provider)}</strong> (${escapeHtml(def.model || '?')})`;
      } else {
        const left = trial.calls_remaining ?? 50;
        chip.innerHTML = `🎁 מצב ניסיון — נותרו <strong>${left}/${trial.calls_max || 50}</strong> הפעלות. <a href="#" id="bp-add-provider-link">הוסף ספק AI →</a>`;
        document.getElementById('bp-add-provider-link')?.addEventListener('click', (e) => {
          e.preventDefault();
          chrome.tabs.create({ url: 'https://app.organicai.doogree.co.il/#integrations:ai' });
        });
      }
    } catch {}
  })();
  $('bp-save-btn').addEventListener('click', async () => {
    const body = {
      business_description: $('bp-business').value.trim(),
      audience:             $('bp-audience').value.trim(),
      goal:                 $('bp-goal').value,
      tone:                 $('bp-tone').value,
      competitors:          $('bp-competitors').value.trim() || null,
    };
    if (!body.business_description || !body.audience) {
      $('bp-status').textContent = '❌ שתי השאלות הראשונות חובה';
      return;
    }
    $('bp-status').textContent = '⏳ שומר...';
    const r = await api('ai-mode/brand-profile', { method: 'POST', body: JSON.stringify(body) });
    if (r.ok) {
      $('bp-status').textContent = '✅ נשמר';
      toast('🎉 פרופיל נשמר. עכשיו תוכל להפעיל מצב AI.', 'ok', 5000);
      wizard.hidden = true;
      refresh();
    } else {
      $('bp-status').textContent = '❌ ' + (r.error || 'שגיאה');
    }
  });

  // Live progress pushes from the service worker while the popup is open.
  chrome.runtime.onMessage.addListener((m) => {
    if (m?.type === 'AI_SCAN_PROGRESS' && m.state) {
      renderScanProgress(m.state);
      if (m.state.phase === 'done') {
        toast(m.state.message || '✅ הסריקה הושלמה', 'ok', 6000);
        refresh();
      } else if (m.state.phase === 'error') {
        toast('❌ ' + (m.state.error || 'שגיאת סריקה'), 'err', 6000);
      }
    }
    // A new scan screenshot arrived — append it live to the strip if visible.
    if (m?.type === 'SCAN_SHOT' && m.shot?.dataUrl) {
      const strip = document.getElementById('scan-shots');
      if (strip) {
        strip.insertAdjacentHTML('beforeend',
          `<a href="${m.shot.dataUrl}" target="_blank" title="${escapeHtml(m.shot.label||'')}" style="flex:0 0 auto;"><img src="${m.shot.dataUrl}" style="height:90px;border-radius:6px;border:1px solid var(--border,#ccc);display:block;"></a>`);
        while (strip.children.length > 12) strip.firstElementChild?.remove();
      }
    }
  });

  refresh();
}
document.addEventListener('DOMContentLoaded', aiModeInit);
if (document.readyState !== 'loading') aiModeInit();
