/* Al Moasis · Dashboard v3 — Operations tab
   Goals (autonomy/agenda), pending escalations, scheduled cron jobs.
   All endpoints exist; this just renders them in v3 design. */

'use strict';

(function () {
  const $ = (s) => document.querySelector(s);
  const api = () => window.__moasis?.api;
  const applyIcons = () => window.__moasis?.applyIcons?.();
  const esc = (s) => String(s ?? '').replace(/[&<>"']/g,(c)=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c]));

  async function loadAgenda() {
    const root = $('[data-bind="ops-agenda-list"]');
    if (!root) return;
    try {
      // (v3.0.5 fix) Backend returns `{ goals: [...] }`. The previous
      // `r?.data || r` extraction got the whole envelope object, which
      // failed `Array.isArray` and rendered the empty state — that's
      // why a freshly-created goal "disappeared".
      const r = await api()('/api/autonomy/agenda');
      const items = Array.isArray(r?.goals) ? r.goals
                  : Array.isArray(r?.data)  ? r.data
                  : Array.isArray(r)        ? r
                  : [];
      if (items.length === 0) {
        root.innerHTML = empty('لا توجد أهداف بعد. اضغط "هدف جديد" لإضافة أول هدف.');
        return;
      }
      root.innerHTML = items.map(agendaRow).join('');
      applyIcons();
      // Wire archive buttons
      root.querySelectorAll('[data-goal-archive]').forEach((b) => {
        b.addEventListener('click', async () => {
          const id = b.dataset.goalArchive;
          try {
            await api()(`/api/autonomy/agenda/${encodeURIComponent(id)}/archive`, { method: 'POST' });
            await loadAgenda();
          } catch (err) {
            alert(`فشل الأرشفة: ${err.message}`);
          }
        });
      });
      // Wire "show activity" + "pursue now" — the visibility the owner asked
      // for: see the agent's real steps on a goal, or kick it off on demand.
      root.querySelectorAll('[data-goal-activity]').forEach((b) => {
        b.addEventListener('click', () => toggleGoalActivity(b.dataset.goalActivity, b));
      });
      root.querySelectorAll('[data-goal-pursue]').forEach((b) => {
        b.addEventListener('click', () => pursueGoalNow(b.dataset.goalPursue, b));
      });
      // (v3.0.5) Progress bars are READ-ONLY — the agent reports
      // progress via journal entries (goal_progress kind) and we
      // surface the resulting current_value here. The owner doesn't
      // drag a slider to fake forward motion. If a goal needs a manual
      // bump, the owner does it through the chat ("mark goal X done")
      // and the agent records it explicitly.
    } catch (err) {
      root.innerHTML = empty(`تعذّر التحميل: ${err.message}`);
    }
  }

  // ─── Pending sender approvals (WhatsApp) ──────────────────────────
  // Customers who DM'd the agent for the first time need owner approval
  // before the agent starts auto-replying. This card lists them; approve
  // → allowlist + welcome; deny → polite decline.
  async function loadApprovals() {
    // Insert the approvals card just below the escalations card on first call
    let root = document.querySelector('[data-bind="ops-approvals-list"]');
    if (!root) {
      const escSection = document.querySelector('[data-bind="ops-escalations-list"]')?.closest('section');
      if (escSection) {
        const newSection = document.createElement('section');
        newSection.className = 'bg-white rounded-2xl border border-line shadow-card overflow-hidden';
        newSection.innerHTML = `
          <div class="px-5 py-4 border-b border-line flex items-center gap-2">
            <span class="w-7 h-7 rounded-lg bg-emerald-50 flex items-center justify-center">
              <i data-lucide="user-check" class="w-4 h-4 text-emerald-600"></i>
            </span>
            <h2 class="font-semibold text-[15px] text-ink">طلبات تواصل جديدة</h2>
          </div>
          <div data-bind="ops-approvals-list">
            <div class="p-5 text-center text-[13px] text-muted">جارٍ التحميل…</div>
          </div>`;
        escSection.parentNode.insertBefore(newSection, escSection.nextSibling);
        root = newSection.querySelector('[data-bind="ops-approvals-list"]');
      }
    }
    if (!root) return;
    try {
      const r = await api()('/api/whatsapp/approvals/pending');
      const items = r?.data || r || [];
      if (!Array.isArray(items) || items.length === 0) {
        root.innerHTML = empty('لا توجد طلبات تواصل تنتظر موافقتك.');
        return;
      }
      root.innerHTML = items.map(approvalRow).join('');
      applyIcons();
      root.querySelectorAll('[data-approve]').forEach((b) =>
        b.addEventListener('click', () => decideApproval(b.dataset.approve, 'approve')));
      root.querySelectorAll('[data-deny]').forEach((b) =>
        b.addEventListener('click', () => decideApproval(b.dataset.deny, 'deny')));
    } catch (err) {
      root.innerHTML = empty(`تعذّر التحميل: ${err.message}`);
    }
  }

  function approvalRow(a) {
    const phone = a.phone || a.from || a.sender || '—';
    const name = a.name || a.display_name || '';
    const preview = a.first_message || a.preview || a.context || '';
    return `
      <div class="px-5 py-4 border-b border-soft last:border-0">
        <div class="flex items-start gap-3">
          <span class="w-9 h-9 rounded-full bg-emerald-100 flex items-center justify-center text-emerald-700 font-semibold text-[13px] shrink-0">
            ${esc((name || phone || '?').trim().charAt(0))}
          </span>
          <div class="flex-1 min-w-0">
            <div class="font-semibold text-[14px] text-ink">${esc(name || 'مرسل جديد')}</div>
            <div class="text-[11.5px] text-muted font-num" dir="ltr">${esc(phone)}</div>
            ${preview ? `<div class="text-[12.5px] text-body mt-1.5 line-clamp-2">"${esc(preview)}"</div>` : ''}
            <div class="flex gap-2 mt-3">
              <button class="btn-primary py-1.5 px-3 text-[12px]" data-approve="${esc(a.id)}">
                <i data-lucide="check" class="w-3.5 h-3.5"></i><span>قبول + ردّ ترحيب</span>
              </button>
              <button class="btn-outline py-1.5 px-3 text-[12px]" data-deny="${esc(a.id)}">
                <i data-lucide="x" class="w-3.5 h-3.5"></i><span>رفض</span>
              </button>
            </div>
          </div>
        </div>
      </div>`;
  }

  async function decideApproval(id, decision) {
    try {
      await api()(`/api/whatsapp/approvals/${encodeURIComponent(id)}/${decision}`, { method: 'POST' });
      await loadApprovals();
    } catch (err) {
      alert(`فشل: ${err.message}`);
    }
  }

  // ─── Inbound access control (who can DM the agent + allow list) ────
  // Lets the owner choose how strangers are handled (auto / ask / never)
  // and manage the permanent allow list — backed by /api/autonomy/policies
  // (inbound_access) and /api/autonomy/allowlist. All endpoints already exist.
  const ACCESS_MODES = [
    { k: 'auto',  t: 'تلقائي', d: 'أي شخص يقدر يراسل المؤسس ويرد عليه فوراً.' },
    { k: 'ask',   t: 'مراجعة', d: 'الغرباء ينتظرون موافقتك قبل أي رد. المعروفون يُرد عليهم فوراً.' },
    { k: 'never', t: 'مغلق',  d: 'فقط قائمة السماح. البقية تُتجاهل بصمت.' },
  ];

  async function loadAccessControl() {
    let root = document.querySelector('[data-bind="ops-access-card"]');
    if (!root) {
      const anchor = document.querySelector('[data-bind="ops-approvals-list"]')?.closest('section')
                  || document.querySelector('[data-bind="ops-escalations-list"]')?.closest('section');
      if (anchor) {
        const sec = document.createElement('section');
        sec.className = 'bg-white rounded-2xl border border-line shadow-card overflow-hidden';
        sec.innerHTML = `
          <div class="px-5 py-4 border-b border-line flex items-center gap-2">
            <span class="w-7 h-7 rounded-lg bg-emerald-50 flex items-center justify-center">
              <i data-lucide="shield-check" class="w-4 h-4 text-emerald-600"></i>
            </span>
            <h2 class="font-semibold text-[15px] text-ink">من يمكنه مراسلة المؤسس</h2>
          </div>
          <div data-bind="ops-access-card" class="p-5 space-y-5">
            <div class="text-center text-[13px] text-muted">جارٍ التحميل…</div>
          </div>`;
        anchor.parentNode.insertBefore(sec, anchor.nextSibling);
        root = sec.querySelector('[data-bind="ops-access-card"]');
      }
    }
    if (!root) return;
    try {
      const [polR, listR] = await Promise.all([
        api()('/api/autonomy/policies'),
        api()('/api/autonomy/allowlist'),
      ]);
      const policies = polR?.policies || polR?.data || [];
      const mode = policies.find((p) => p.policy_key === 'inbound_access')?.mode || 'auto';
      const contacts = listR?.contacts || listR?.allowlist || listR?.data || (Array.isArray(listR) ? listR : []);
      root.innerHTML = renderAccess(mode, contacts);
      applyIcons();
      wireAccess(root);
    } catch (err) {
      root.innerHTML = empty(`تعذّر التحميل: ${err.message}`);
    }
  }

  function renderAccess(mode, contacts) {
    const modeBtns = ACCESS_MODES.map((m) => `
      <button data-access-mode="${m.k}" class="flex-1 rounded-xl border px-3 py-2.5 text-right transition ${m.k === mode ? 'border-emerald-500 bg-emerald-50' : 'border-line bg-white hover:bg-soft'}">
        <div class="font-semibold text-[13px] text-ink flex items-center gap-1.5">
          ${m.k === mode ? '<i data-lucide="check-circle" class="w-3.5 h-3.5 text-emerald-600"></i>' : ''}${m.t}
        </div>
        <div class="text-[11px] text-muted mt-0.5 leading-snug">${m.d}</div>
      </button>`).join('');
    const rows = (contacts || []).length ? contacts.map((c) => `
      <div class="flex items-center gap-2 py-2 border-b border-soft last:border-0">
        <span class="w-7 h-7 rounded-full bg-emerald-100 flex items-center justify-center text-emerald-700 text-[12px] font-semibold shrink-0">${esc((c.display_name || c.identifier || '?').trim().charAt(0))}</span>
        <div class="flex-1 min-w-0">
          <div class="text-[13px] text-ink truncate">${esc(c.display_name || '—')} ${c.role && c.role !== 'contact' ? `<span class="text-[10px] text-emerald-600">(${esc(c.role)})</span>` : ''}</div>
          <div class="text-[11px] text-muted font-num" dir="ltr">${esc(c.channel || '')} · ${esc(c.identifier || '')}</div>
        </div>
        <button data-access-del="${esc(c.channel || 'whatsapp')}|${esc(c.identifier || '')}" class="text-rose-500 hover:bg-rose-50 rounded-lg p-1.5" title="حذف"><i data-lucide="trash-2" class="w-3.5 h-3.5"></i></button>
      </div>`).join('') : empty('لا أحد في قائمة السماح بعد.');
    return `
      <div>
        <div class="text-[12px] text-muted mb-2">وضع استقبال الرسائل من الأرقام غير المعروفة:</div>
        <div class="flex gap-2">${modeBtns}</div>
      </div>
      <div>
        <div class="text-[12px] text-muted mb-2">قائمة السماح — يُرد عليهم فوراً دائماً مهما كان الوضع:</div>
        <div class="flex gap-2 mb-3">
          <input data-access-id placeholder="+9665XXXXXXXX أو tg-12345" dir="ltr" class="flex-1 rounded-lg border border-line px-3 py-2 text-[13px]"/>
          <input data-access-name placeholder="الاسم (اختياري)" class="w-28 rounded-lg border border-line px-3 py-2 text-[13px]"/>
          <button data-access-add class="btn-primary px-3 py-2 text-[12px]"><i data-lucide="plus" class="w-3.5 h-3.5"></i><span>إضافة</span></button>
        </div>
        <div data-bind="access-list">${rows}</div>
      </div>`;
  }

  function wireAccess(root) {
    root.querySelectorAll('[data-access-mode]').forEach((b) => b.addEventListener('click', async () => {
      try {
        await api()('/api/autonomy/policies', { method: 'POST', body: JSON.stringify({ policy_key: 'inbound_access', mode: b.dataset.accessMode }) });
        await loadAccessControl();
      } catch (err) { alert(`فشل تغيير الوضع: ${err.message}`); }
    }));
    const addBtn = root.querySelector('[data-access-add]');
    if (addBtn) addBtn.addEventListener('click', async () => {
      const id = root.querySelector('[data-access-id]')?.value?.trim();
      const name = root.querySelector('[data-access-name]')?.value?.trim();
      if (!id) return;
      const channel = (id.startsWith('tg-') || id.startsWith('@')) ? 'telegram' : id.includes('@') ? 'email' : 'whatsapp';
      try {
        await api()('/api/autonomy/allowlist', { method: 'POST', body: JSON.stringify({ channel, identifier: id, display_name: name || undefined, role: 'contact' }) });
        await loadAccessControl();
      } catch (err) { alert(`فشل الإضافة: ${err.message}`); }
    });
    root.querySelectorAll('[data-access-del]').forEach((b) => b.addEventListener('click', async () => {
      const [channel, identifier] = b.dataset.accessDel.split('|');
      try {
        await api()(`/api/autonomy/allowlist/${encodeURIComponent(channel)}/${encodeURIComponent(identifier)}`, { method: 'DELETE' });
        await loadAccessControl();
      } catch (err) { alert(`فشل الحذف: ${err.message}`); }
    }));
  }

  function agendaRow(g) {
    // (v3.0.5) Progress is computed from the agent's actual journal —
    // current_value vs target_value when a target was set, or a step
    // count otherwise. The owner doesn't drag a slider to fake
    // progress; the AGENT updates it as it does real work.
    const current = Number(g.current_value ?? 0);
    const target = Number(g.target_value ?? 0);
    const unit = g.unit || '';
    const meta = g.metadata || {};
    const lastPursued = meta.last_pursued_at ? new Date(meta.last_pursued_at) : null;
    const fails = Number(meta.consecutive_pursuit_fails ?? 0);
    const autoExecute = meta.auto_execute !== false; // default true

    // Honest progress: a percentage exists ONLY when the goal has a numeric
    // target (current/target). A goal with no target has no measurable
    // percent — we show a qualitative status instead of manufacturing a bar.
    // (Previously targetless goals rendered current*10 capped at 100, so any
    // goal the agent touched showed a fake full bar.)
    const hasTarget = target > 0;
    const isAchieved = g.status === 'achieved';
    const progressPct = hasTarget
      ? Math.min(100, Math.round((current / target) * 100))
      : (isAchieved ? 100 : null);
    const stepLabel = hasTarget
      ? `${current}${unit ? ' ' + esc(unit) : ''} / ${target}${unit ? ' ' + esc(unit) : ''}`
      : isAchieved ? 'مكتمل' : 'قيد التنفيذ';

    const lastPursuedAr = lastPursued
      ? formatRelativeAr(lastPursued)
      : 'لم يُلمس بعد';

    const statusChip = fails >= 3
      ? `<span class="px-2 py-0.5 rounded-full bg-rose-50 text-rose-700 text-[10px]" title="${esc(String(meta.last_pursuit_failure_detail || ''))}">متوقّف — 3 محاولات فاشلة</span>`
      : !autoExecute
        ? `<span class="px-2 py-0.5 rounded-full bg-slate-100 text-slate-600 text-[10px]">يدوي</span>`
        : `<span class="px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 text-[10px]">تلقائي</span>`;

    // Bar fills to a real percentage only when one exists. Targetless,
    // not-yet-achieved goals get an empty track — no fake fill.
    const barInner = progressPct !== null
      ? `<div class="h-1.5 bg-soft rounded-full overflow-hidden">
           <div class="h-full bg-emerald-500 rounded-full transition-[width] duration-500" style="width: ${progressPct}%"></div>
         </div>`
      : `<div class="h-1.5 bg-soft rounded-full overflow-hidden"></div>`;

    return `
      <div class="px-5 py-4 border-b border-soft last:border-0 hover:bg-page transition" data-goal-id="${esc(g.id)}">
        <div class="flex items-start gap-3">
          <span class="w-8 h-8 rounded-lg bg-emerald-50 flex items-center justify-center shrink-0">
            <i data-lucide="target" class="w-4 h-4 text-emerald-600"></i>
          </span>
          <div class="flex-1 min-w-0">
            <div class="flex items-center gap-2">
              <div class="font-semibold text-[14px] text-ink flex-1 truncate">${esc(g.title || g.goal || g.summary || 'هدف بدون عنوان')}</div>
              ${statusChip}
              <button class="p-1 text-muted hover:text-rose-600 transition" data-goal-archive="${esc(g.id)}" title="أرشف الهدف">
                <i data-lucide="archive" class="w-3.5 h-3.5"></i>
              </button>
            </div>
            ${g.description ? `<div class="text-[12.5px] text-body mt-0.5 line-clamp-2">${esc(g.description)}</div>` : ''}
            <div class="mt-2.5">
              ${barInner}
              <div class="mt-1.5 flex items-center justify-between text-[11px] text-muted">
                <span class="font-num">${stepLabel}${progressPct !== null ? ` · ${progressPct}%` : ''}</span>
                <span title="آخر سعي تلقائي">آخر تقدّم: ${esc(lastPursuedAr)}</span>
              </div>
            </div>
            <div class="mt-2 flex items-center gap-3">
              <button class="text-[11px] text-emerald-700 hover:underline flex items-center gap-1" data-goal-activity="${esc(g.id)}">
                <i data-lucide="list" class="w-3.5 h-3.5"></i><span>اعرض النشاط</span>
              </button>
              <button class="text-[11px] text-emerald-700 hover:underline flex items-center gap-1" data-goal-pursue="${esc(g.id)}">
                <i data-lucide="play" class="w-3.5 h-3.5"></i><span>اعمل عليه الآن</span>
              </button>
            </div>
            <div class="goal-activity hidden mt-2 rounded-lg bg-page border border-soft p-3" data-goal-activity-panel="${esc(g.id)}"></div>
          </div>
        </div>
      </div>`;
  }

  // Render the per-goal activity timeline (real steps the agent took) from
  // /api/autonomy/agenda/:id/activity. This is the "where is the agent at"
  // view — pursuit status + a chronological list of journaled actions.
  async function toggleGoalActivity(goalId, btn) {
    const panel = document.querySelector(`[data-goal-activity-panel="${goalId}"]`);
    if (!panel) return;
    if (!panel.classList.contains('hidden')) { panel.classList.add('hidden'); return; }
    panel.classList.remove('hidden');
    panel.innerHTML = `<div class="text-[12px] text-muted text-center py-2">جارٍ التحميل…</div>`;
    try {
      const r = await api()(`/api/autonomy/agenda/${encodeURIComponent(goalId)}/activity`);
      const p = r?.pursuit || {};
      const acts = r?.activity || [];
      const outcomeAr = p.last_outcome === 'success' ? '✅ نجاح'
        : p.last_outcome === 'failure' ? '⚠️ لم يُحرز تقدماً' : '—';
      const statusLine = `
        <div class="text-[11px] text-muted mb-2 flex flex-wrap gap-x-4 gap-y-1">
          <span>آخر محاولة: ${p.last_pursued_at ? esc(formatRelativeAr(new Date(p.last_pursued_at))) : 'لم يُلمس بعد'}</span>
          <span>النتيجة: ${outcomeAr}</span>
          ${p.consecutive_fails > 0 ? `<span class="text-rose-600">محاولات فاشلة متتالية: ${p.consecutive_fails}</span>` : ''}
          <span>${p.auto_execute ? 'تلقائي' : 'يدوي'}</span>
        </div>
        ${p.failure_detail ? `<div class="text-[11px] text-rose-600 mb-2">سبب آخر إخفاق: ${esc(String(p.failure_detail))}</div>` : ''}`;
      if (acts.length === 0) {
        panel.innerHTML = statusLine + `<div class="text-[12px] text-muted py-1">لا توجد خطوات مُسجّلة بعد على هذا الهدف. اضغط "اعمل عليه الآن" ليبدأ المؤسس.</div>`;
        applyIcons();
        return;
      }
      const rows = acts.map((a) => {
        const ok = String(a.outcome || '').toLowerCase() === 'success';
        const icon = ok ? '✅' : (String(a.outcome).toLowerCase() === 'failure' ? '❌' : '•');
        const when = a.created_at ? formatRelativeAr(new Date(a.created_at)) : '';
        const what = esc(a.action || a.kind || 'إجراء');
        const why = a.reason ? ` — ${esc(String(a.reason).slice(0, 80))}` : '';
        return `<div class="flex items-start gap-2 text-[12px] py-1 border-b border-soft last:border-0">
          <span class="shrink-0">${icon}</span>
          <span class="flex-1 min-w-0"><span class="text-ink" dir="auto">${what}</span><span class="text-muted">${why}</span></span>
          <span class="text-[10px] text-muted shrink-0">${esc(when)}</span>
        </div>`;
      }).join('');
      panel.innerHTML = statusLine + `<div class="text-[11px] font-semibold text-ink mb-1">سجل الخطوات (${acts.length})</div>` + rows;
      applyIcons();
    } catch (err) {
      panel.innerHTML = `<div class="text-[12px] text-rose-600">تعذّر تحميل النشاط: ${esc(err.message)}</div>`;
    }
  }

  async function pursueGoalNow(goalId, btn) {
    const original = btn.innerHTML;
    btn.innerHTML = `<span>جارٍ التشغيل…</span>`;
    btn.disabled = true;
    try {
      await api()(`/api/autonomy/agenda/${encodeURIComponent(goalId)}/pursue`, { method: 'POST' });
      // Open the activity panel so the user watches the steps land.
      const panel = document.querySelector(`[data-goal-activity-panel="${goalId}"]`);
      if (panel) panel.classList.add('hidden'); // force re-fetch
      await toggleGoalActivity(goalId, btn);
    } catch (err) {
      alert(`تعذّر التشغيل: ${err.message}`);
    } finally {
      btn.innerHTML = original;
      btn.disabled = false;
      applyIcons();
    }
  }

  /** Compact Arabic relative-time formatter ("منذ 5 د", "منذ 3 س", "أمس"). */
  function formatRelativeAr(date) {
    const diffMs = Date.now() - date.getTime();
    if (diffMs < 0) return 'الآن';
    const sec = Math.floor(diffMs / 1000);
    if (sec < 60) return 'الآن';
    const min = Math.floor(sec / 60);
    if (min < 60) return `منذ ${min} د`;
    const hr = Math.floor(min / 60);
    if (hr < 24) return `منذ ${hr} س`;
    const day = Math.floor(hr / 24);
    if (day === 1) return 'أمس';
    if (day < 30) return `منذ ${day} يوم`;
    return date.toISOString().slice(0, 10);
  }

  async function loadEscalations() {
    const root = $('[data-bind="ops-escalations-list"]');
    if (!root) return;
    try {
      const r = await api()('/api/autonomy/escalations');
      const items = r?.data || r || [];
      const pending = (Array.isArray(items) ? items : []).filter((e) => !e.resolved_at && e.status !== 'resolved');
      if (pending.length === 0) {
        root.innerHTML = empty('لا توجد قرارات تنتظر موافقتك.');
        return;
      }
      root.innerHTML = pending.map(escRow).join('');
      applyIcons();
      root.querySelectorAll('[data-esc-approve]').forEach((b) => b.addEventListener('click', () => resolveEsc(b.dataset.escApprove, 'approve')));
      root.querySelectorAll('[data-esc-deny]').forEach((b) => b.addEventListener('click', () => resolveEsc(b.dataset.escDeny, 'deny')));
    } catch (err) {
      root.innerHTML = empty(`تعذّر التحميل: ${err.message}`);
    }
  }

  function escRow(e) {
    return `
      <div class="px-5 py-4 border-b border-soft last:border-0">
        <div class="flex items-start gap-3">
          <span class="w-8 h-8 rounded-lg bg-amber-50 flex items-center justify-center shrink-0">
            <i data-lucide="alert-circle" class="w-4 h-4 text-amber-600"></i>
          </span>
          <div class="flex-1 min-w-0">
            <div class="font-semibold text-[14px] text-ink">${esc(e.title || e.reason || 'قرار يحتاج موافقة')}</div>
            ${e.context ? `<div class="text-[12.5px] text-body mt-1 line-clamp-3">${esc(e.context)}</div>` : ''}
            <div class="flex gap-2 mt-3">
              <button class="btn-primary py-1.5 px-3 text-[12px]" data-esc-approve="${esc(e.id)}">
                <i data-lucide="check" class="w-3.5 h-3.5"></i>
                <span>موافق</span>
              </button>
              <button class="btn-outline py-1.5 px-3 text-[12px]" data-esc-deny="${esc(e.id)}">
                <i data-lucide="x" class="w-3.5 h-3.5"></i>
                <span>ارفض</span>
              </button>
            </div>
          </div>
        </div>
      </div>`;
  }

  async function resolveEsc(id, decision) {
    try {
      await api()(`/api/autonomy/escalations/${encodeURIComponent(id)}/resolve`, {
        method: 'POST',
        body: JSON.stringify({ decision }),
      });
      loadEscalations();
    } catch (err) {
      alert(`فشل: ${err.message}`);
    }
  }

  async function loadCrons() {
    const root = $('[data-bind="ops-cron-list"]');
    if (!root) return;
    try {
      const r = await api()('/api/cron/jobs');
      const items = r?.data || r?.jobs || r || [];
      if (!Array.isArray(items) || items.length === 0) {
        root.innerHTML = empty('لا توجد مهام دورية مجدولة.');
        return;
      }
      root.innerHTML = items.map(cronRow).join('');
      applyIcons();
    } catch (err) {
      root.innerHTML = empty(`تعذّر التحميل: ${err.message}`);
    }
  }

  function cronRow(j) {
    const last = j.last_run_at ? new Date(j.last_run_at).toLocaleString('ar-SA', { dateStyle: 'short', timeStyle: 'short' }) : 'لم يُنفّذ بعد';
    return `
      <div class="px-5 py-3.5 border-b border-soft last:border-0 flex items-center gap-3">
        <span class="w-8 h-8 rounded-lg bg-emerald-50 flex items-center justify-center shrink-0">
          <i data-lucide="clock" class="w-4 h-4 text-emerald-600"></i>
        </span>
        <div class="flex-1 min-w-0">
          <div class="font-medium text-[13.5px] text-ink truncate">${esc(j.name || j.id)}</div>
          <div class="text-[11px] text-muted">
            <span class="font-num" dir="ltr">${esc(j.schedule || '')}</span>
            ${j.description ? ` · ${esc(j.description)}` : ''}
          </div>
        </div>
        <div class="text-[11px] text-muted">${esc(last)}</div>
      </div>`;
  }

  function empty(msg) { return `<div class="p-5 text-center text-[13px] text-muted">${esc(msg)}</div>`; }

  // Goal-creation modal (Claude-Code /goal style — agent will pursue
  // the goal autonomously by spawning subagents and reporting back).
  function showGoalModal() {
    let modal = document.getElementById('goal-modal');
    if (!modal) {
      modal = document.createElement('div');
      modal.id = 'goal-modal';
      modal.className = 'moasis-modal';
      modal.innerHTML = `
        <div class="moasis-modal-card max-w-[520px]">
          <h2 class="font-display font-bold text-[20px] text-ink mb-2">هدف جديد</h2>
          <p class="text-[13px] text-body mb-5 leading-[1.7]">
            صف الهدف بوضوح. المؤسس سيعمل عليه تلقائياً — يستدعي وكلاء فرعيين عند الحاجة ويُحدّث التقدّم في الدردشة.
          </p>
          <label class="block text-[13px] font-medium text-ink mb-1.5">عنوان الهدف</label>
          <input id="goal-modal-title" class="w-full px-3 py-2 bg-white border border-line rounded-lg outline-none text-[14px] mb-3 focus:border-emerald-600" placeholder="مثلاً: اجمع 50 ليد لمكاتب محاماة في جدة" />
          <label class="block text-[13px] font-medium text-ink mb-1.5">تفاصيل (اختياري)</label>
          <textarea id="goal-modal-desc" rows="3" class="w-full px-3 py-2 bg-white border border-line rounded-lg outline-none text-[14px] mb-3 focus:border-emerald-600" placeholder="معايير النجاح، الموعد النهائي، الموارد المسموح بها، إلخ"></textarea>
          <label class="flex items-center gap-2 mb-4 cursor-pointer">
            <input type="checkbox" id="goal-modal-auto" class="accent-emerald-600" checked />
            <span class="text-[13px] text-ink">نفّذ تلقائياً (المؤسس يبدأ فوراً ويُتابع للنهاية)</span>
          </label>
          <div class="text-[12px] text-rose-600 mb-2 hidden" id="goal-modal-error"></div>
          <div class="flex gap-2">
            <button class="btn-outline flex-1" id="goal-modal-cancel">إلغاء</button>
            <button class="btn-primary flex-1" id="goal-modal-save">
              <i data-lucide="rocket" class="w-4 h-4"></i>
              <span>أنشئ وابدأ</span>
            </button>
          </div>
        </div>`;
      document.body.appendChild(modal);
      applyIcons();
      modal.querySelector('#goal-modal-cancel').addEventListener('click', () => modal.classList.add('hidden'));
      modal.querySelector('#goal-modal-save').addEventListener('click', () => saveGoal(modal));
      modal.addEventListener('click', (e) => { if (e.target === modal) modal.classList.add('hidden'); });
    }
    // Reset fields
    modal.querySelector('#goal-modal-title').value = '';
    modal.querySelector('#goal-modal-desc').value = '';
    modal.querySelector('#goal-modal-auto').checked = true;
    modal.querySelector('#goal-modal-error').classList.add('hidden');
    modal.classList.remove('hidden');
    setTimeout(() => modal.querySelector('#goal-modal-title').focus(), 50);
  }

  async function saveGoal(modal) {
    const title = modal.querySelector('#goal-modal-title').value.trim();
    const desc  = modal.querySelector('#goal-modal-desc').value.trim();
    const autoExecute = modal.querySelector('#goal-modal-auto').checked;
    const errEl = modal.querySelector('#goal-modal-error');
    if (!title) { errEl.textContent = 'عنوان الهدف مطلوب'; errEl.classList.remove('hidden'); return; }
    const saveBtn = modal.querySelector('#goal-modal-save');
    const orig = saveBtn.innerHTML;
    saveBtn.disabled = true;
    saveBtn.innerHTML = '<i data-lucide="loader-circle" class="w-4 h-4 animate-spin"></i><span>جارٍ الإنشاء…</span>';
    applyIcons();
    try {
      const r = await api()('/api/autonomy/agenda', {
        method: 'POST',
        body: JSON.stringify({ title, description: desc, auto_execute: autoExecute }),
      });
      modal.classList.add('hidden');
      await loadAgenda();
      // If auto-execute, send the goal as a chat message so the agent
      // starts working immediately. The chat thread becomes the
      // execution log — every step (web_search, create_excel, etc.)
      // renders as a pill, and the artifact card shows the deliverable.
      // (v3.0.5 fix) Backend returns `{ goal: {...} }` — read from that
      // shape first so the kickoff message can reference the goal ID.
      if (autoExecute && window.__moasis?.switchPane) {
        const goalId = r?.goal?.id || r?.data?.id || r?.id;
        const kickoff = `ابدأ تنفيذ هذا الهدف الآن: "${title}"${desc ? `\n\nالتفاصيل: ${desc}` : ''}\n\nاعمل بشكل ذاتي. استدعِ وكلاء فرعيين لو احتجت. ابلغني بكل خطوة في الدردشة. لا تنتظر إذني بين الخطوات.`;
        window.__moasis.switchPane('chat');
        const input = document.getElementById('chat-input');
        if (input) {
          input.value = kickoff;
          // Auto-fire after a tiny delay so the pane switch is visible
          setTimeout(() => {
            const sendBtn = document.querySelector('[data-action="send"]');
            if (sendBtn) sendBtn.click();
          }, 300);
        }
      }
    } catch (err) {
      errEl.textContent = `فشل: ${err.message}`;
      errEl.classList.remove('hidden');
    } finally {
      saveBtn.disabled = false;
      saveBtn.innerHTML = orig;
      applyIcons();
    }
  }

  function wire() {
    document.addEventListener('click', (e) => {
      if (e.target.closest?.('[data-action="ops-add-goal"]')) showGoalModal();
    });
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', wire);
  else wire();

  function onShow() { loadAgenda(); loadEscalations(); loadApprovals(); loadAccessControl(); loadCrons(); }
  window.__moasisOperations = { onShow };
})();
