// dashboard-ai-lead-analysis-button-card-i.js — extracted verbatim from dashboard.js (pure move).

// ── AI Lead Analysis (button + card in CRM drawers) ───────────────
//
// Opinionated "is this a real lead?" verdict with structured reasoning,
// signals_for chips, red_flags chips, and a suggested next step. Runs
// against existing CRM data + opportunistically queues a LinkedIn refresh
// when data is stale (the actual scrape happens via the extension's
// scrape-queue picker the next time the user visits that profile).

const VERDICT_STYLE = {
  qualified: { label: "Qualified", color: "var(--green)", bg: "var(--green-soft)", icon: "🟢" },
  marginal: { label: "Marginal", color: "var(--yellow)", bg: "var(--yellow-soft)", icon: "🟡" },
  not_a_lead: { label: "Not a lead", color: "var(--red)", bg: "var(--red-soft)", icon: "🔴" },
};

const FRESHNESS_HINT = {
  fresh: { label: "fresh data", color: "var(--text-3)" },
  stale: { label: "data is stale — refresh queued", color: "var(--yellow)" },
  thin: { label: "thin profile — limited evidence", color: "var(--yellow)" },
};

// Renders the AI analysis result inline as a card. `result` shape matches
// the analyzeLead() return: verdict, confidence, headline, reasoning,
// signals_for[], red_flags[], suggested_action, data_freshness, generated_at.
function renderLeadAnalysisCard(result) {
  const v = VERDICT_STYLE[result.verdict] || VERDICT_STYLE.marginal;
  const fresh = FRESHNESS_HINT[result.data_freshness] || FRESHNESS_HINT.thin;
  const conf = Math.round((result.confidence || 0) * 100);

  const card = el("div", {
    style: `border:1px solid ${v.color}33;background:${v.bg};border-left:3px solid ${v.color};border-radius:var(--radius-md);padding:14px 16px;margin:10px 0;`,
  });

  // Header — verdict + confidence bar.
  card.appendChild(
    el("div", { style: "display:flex;align-items:center;gap:10px;margin-bottom:8px;" }, [
      el("span", { style: "font-size:18px;" }, v.icon),
      el("div", { style: "flex:1;min-width:0;" }, [
        el(
          "div",
          {
            style: `font-weight:700;color:${v.color};font-size:13px;text-transform:uppercase;letter-spacing:0.05em;`,
          },
          v.label,
        ),
        el("div", { class: "muted small" }, `${conf}% confidence · ${fresh.label}`),
      ]),
    ]),
  );

  // Headline.
  if (result.headline) {
    card.appendChild(
      el(
        "div",
        {
          style:
            "font-size:13px;font-weight:600;color:var(--text-1);margin-bottom:8px;line-height:1.4;",
        },
        result.headline,
      ),
    );
  }

  // Reasoning paragraph.
  if (result.reasoning) {
    card.appendChild(
      el(
        "div",
        {
          class: "muted small",
          style: "line-height:1.6;margin-bottom:10px;",
        },
        result.reasoning,
      ),
    );
  }

  // Signals for / against — chip grids, side by side when both have items.
  const hasFor = (result.signals_for || []).length > 0;
  const hasFlags = (result.red_flags || []).length > 0;
  if (hasFor || hasFlags) {
    const grid = el("div", {
      style: "display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px;",
    });
    if (hasFor) {
      grid.appendChild(
        el("div", {}, [
          el(
            "div",
            {
              class: "muted small",
              style: "margin-bottom:4px;font-weight:600;color:var(--green);",
            },
            "↑ Signals for",
          ),
          el(
            "div",
            { style: "display:flex;flex-wrap:wrap;gap:4px;" },
            result.signals_for.map((s) =>
              el(
                "span",
                {
                  class: "badge badge-green",
                  style: "font-size:10px;line-height:1.4;white-space:normal;",
                },
                s,
              ),
            ),
          ),
        ]),
      );
    }
    if (hasFlags) {
      grid.appendChild(
        el("div", {}, [
          el(
            "div",
            { class: "muted small", style: "margin-bottom:4px;font-weight:600;color:var(--red);" },
            "↓ Red flags",
          ),
          el(
            "div",
            { style: "display:flex;flex-wrap:wrap;gap:4px;" },
            result.red_flags.map((s) =>
              el(
                "span",
                {
                  class: "badge badge-red",
                  style: "font-size:10px;line-height:1.4;white-space:normal;",
                },
                s,
              ),
            ),
          ),
        ]),
      );
    }
    card.appendChild(grid);
  }

  // Suggested action — call-out line at the bottom.
  if (result.suggested_action) {
    card.appendChild(
      el(
        "div",
        {
          style: `border-top:1px solid ${v.color}22;padding-top:8px;font-size:12px;color:var(--text-2);`,
        },
        [
          el("span", { style: `color:${v.color};font-weight:600;` }, "Next step: "),
          document.createTextNode(result.suggested_action),
        ],
      ),
    );
  }

  // Footer metadata.
  const footerBits = [];
  if (result.generated_at) footerBits.push(fmtDate(result.generated_at));
  if (result.from_cache) footerBits.push("cached");
  if (result.enqueued_scrape_task_id)
    footerBits.push(`LI refresh queued #${result.enqueued_scrape_task_id}`);
  if (footerBits.length > 0) {
    card.appendChild(
      el(
        "div",
        { class: "muted small mono", style: "margin-top:6px;font-size:10px;" },
        footerBits.join(" · "),
      ),
    );
  }

  return card;
}

// Top-level helper: button + container that fetches/refreshes the analysis.
// `entityType` is "contact" or "company". `entityId` is the row id. The
// initial render checks the entity row for a cached `ai_lead_analysis_json`
// — if present, we render it immediately (no API call); otherwise the card
// is empty until the user clicks the button.
function buildLeadAnalysisSection(entityType, entityId, cachedJson, cachedAt) {
  const wrap = el("div", { class: "lead-analysis-section", style: "margin: 14px 0;" });
  const resultHost = el("div", { class: "lead-analysis-result" });

  // Render any cached result immediately.
  if (cachedJson) {
    try {
      const parsed = JSON.parse(cachedJson);
      resultHost.appendChild(
        renderLeadAnalysisCard({ ...parsed, generated_at: cachedAt, from_cache: true }),
      );
    } catch {
      /* ignore — bad cache */
    }
  }

  const btnLabel = cachedJson ? "🔄 Re-run AI analysis" : "✨ AI lead analysis";
  const btn = el(
    "button",
    {
      type: "button",
      class: "btn btn-primary btn-tiny",
      style: "width:100%;justify-content:center;",
      title: "Generate an AI verdict on whether this is a qualified lead",
    },
    btnLabel,
  );

  btn.onclick = async () => {
    btn.disabled = true;
    const originalLabel = btn.textContent;
    btn.textContent = "⏳ Starting…";
    resultHost.innerHTML = "";
    const statusLine = el(
      "div",
      {
        class: "muted small",
        style: "padding:10px 14px;text-align:center;",
      },
      "Queueing enrich-then-analyze…",
    );
    resultHost.appendChild(statusLine);

    // Single-row path now routes through the orchestrator so missing fields
    // (twitter, linkedin, website, sector, employees) get backfilled BEFORE
    // the AI runs. waitMs is tighter than bulk (60s vs 180s) since a single
    // entity has at most 5 critical tasks — 60s easily covers them.
    const kind = entityType === "company" ? "companies" : "contacts";
    try {
      const start = await api("crm-enrich-then-analyze", {
        body: { kind, ids: [entityId], force: !!cachedJson, waitMs: 60_000 },
      });
      if (start?.error || !start?.id) throw new Error(start?.error || "no job id");

      // Poll until done. The orchestrator counts the verdict in
      // qualified/marginal/not_a_lead — but to render the rich card we
      // still need the JSON, so after completion we call the single-row
      // analyze endpoint (cache-hit, ~50ms) for the verdict object.
      const pollOnce = async () => {
        const r = await api("crm-enrich-then-analyze-get", { jobId: start.id });
        if (r?.error) throw new Error(r.error);
        return r;
      };

      let snap = start;
      while (snap.status === "running") {
        await new Promise((rs) => setTimeout(rs, snap.phase === "analyzing" ? 1200 : 2500));
        snap = await pollOnce();
        if (snap.phase === "enriching") {
          const e = snap.enrich || {};
          statusLine.textContent =
            e.total_tasks > 0
              ? `Phase 1/2 · Enriching ${e.completed || 0}/${e.total_tasks} signals…`
              : "Phase 1/2 · Checking what's missing…";
        } else if (snap.phase === "analyzing") {
          const e = snap.enrich || {};
          const enrichSummary =
            e.total_tasks > 0
              ? `enriched ${e.completed || 0}/${e.total_tasks}`
              : e.skipped_entities > 0
                ? "already enriched"
                : "skipped enrich";
          statusLine.textContent = `Phase 2/2 · Running AI · ${enrichSummary}`;
        }
      }

      // Final fetch of the cached verdict JSON so we can render the card.
      // analyzeLead is now 24h-cached (we just wrote to it), so this is fast.
      const verdict = await api("crm-lead-analysis", {
        body: { type: entityType, id: entityId, force: false },
      });
      if (verdict?.error) {
        resultHost.innerHTML = "";
        resultHost.appendChild(
          el(
            "div",
            {
              class: "alert-card error",
              style: "margin:0;",
            },
            [
              el("div", { class: "alert-card-title" }, "Analysis failed"),
              el("div", { class: "alert-card-body" }, verdict.error),
            ],
          ),
        );
        toast(`Lead analysis: ${verdict.error}`, "err");
      } else {
        resultHost.innerHTML = "";
        resultHost.appendChild(renderLeadAnalysisCard(verdict));
        const v = VERDICT_STYLE[verdict.verdict] || VERDICT_STYLE.marginal;
        const enrichBit =
          (snap.enrich?.total_tasks || 0) > 0
            ? ` · enriched ${snap.enrich.completed}/${snap.enrich.total_tasks}`
            : "";
        toast(
          `${v.icon} ${v.label} (${Math.round((verdict.confidence || 0) * 100)}%)${enrichBit}`,
          "ok",
          6000,
        );
        if (verdict.enqueued_scrape_task_id) {
          toast("📋 LinkedIn refresh queued — fires next time you open that profile", "info", 6000);
        }
        btn.textContent = "🔄 Re-run AI analysis";
        btn.disabled = false;
        return;
      }
    } catch (err) {
      resultHost.innerHTML = "";
      resultHost.appendChild(
        el(
          "div",
          {
            class: "alert-card error",
            style: "margin:0;",
          },
          [
            el("div", { class: "alert-card-title" }, "Analysis failed"),
            el("div", { class: "alert-card-body" }, err.message || String(err)),
          ],
        ),
      );
    }
    btn.textContent = originalLabel;
    btn.disabled = false;
  };

  wrap.appendChild(btn);
  wrap.appendChild(resultHost);
  return wrap;
}

// Bulk AI lead-analysis runner. Sends an array of contact (or company) ids
// to the server, opens a floating progress widget, polls the job until it
// completes, then refreshes the CRM list and shows a summary toast. The
// widget can be cancelled mid-run; already-inflight AI calls still finish.
//
// Concurrency, cache, and the actual analysis live server-side in
// engine/bulk-lead-analyzer.js — this is purely the driver UI.
async function runBulkLeadAnalysis(
  ids,
  { type = "contact", force = false, skipEnrich = false } = {},
) {
  // The new path uses the enrich-then-analyze orchestrator: fills missing
  // fields (twitter, linkedin, website, sector, employees) for the chosen
  // entities, THEN runs the AI analyzer on fresh data. Single progress
  // widget flips between the two phases.
  //
  // The `kind` parameter for the orchestrator is plural ("companies" /
  // "contacts") whereas the legacy bulk analyze used singular. Map here.
  const kind = type === "company" || type === "companies" ? "companies" : "contacts";
  const start = await api("crm-enrich-then-analyze", { body: { kind, ids, force, skipEnrich } });
  if (start?.error || !start?.id) {
    toast(`Bulk analyze failed: ${start?.error || "no job id"}`, "err");
    return;
  }

  const widget = _openBulkProgressWidget(start);
  let lastSnapshot = start;

  const poll = async () => {
    if (!widget.isOpen()) return; // user closed
    const r = await api("crm-enrich-then-analyze-get", { jobId: start.id }).catch(() => null);
    if (!r || r.error) {
      widget.update({ ...lastSnapshot, _error: r?.error || "polling failed" });
      setTimeout(poll, 2000);
      return;
    }
    lastSnapshot = r;
    widget.update(r);
    if (r.status === "running") {
      // Faster polling during analyze (AI calls finish in ~3-8s each); slower
      // during enrich (tasks take 5-30s each). The orchestrator phase tells us.
      setTimeout(poll, r.phase === "analyzing" ? 1500 : 3000);
    } else {
      // Done — show summary, refresh the list so new verdicts appear.
      const a = r.analyze || {};
      const e = r.enrich || {};
      const enrichBit =
        e.total_tasks > 0
          ? `enriched ${e.completed}/${e.total_tasks}${e.timed_out ? " (timed out)" : ""} · `
          : e.skipped_entities > 0
            ? `${e.skipped_entities} pre-enriched · `
            : "";
      const summary = `${enrichBit}${a.qualified || 0} qualified · ${a.marginal || 0} marginal · ${a.not_a_lead || 0} not · ${a.failed || 0} failed`;
      toast(`✅ AI analysis: ${summary}`, "ok", 8000);
      if (typeof loadCrm === "function") loadCrm();
      setTimeout(() => widget.close(), 4000);
    }
  };
  setTimeout(poll, 800);
}

// Floating bottom-right progress widget. One at a time — re-running while
// active replaces the existing widget.
function _openBulkProgressWidget(initial) {
  const existing = document.getElementById("bulk-lead-widget");
  if (existing) existing.remove();

  let isOpen = true;
  const card = el("div", {
    id: "bulk-lead-widget",
    style: `position:fixed;right:20px;bottom:80px;width:320px;background:var(--bg-1);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:var(--radius-md);box-shadow:0 12px 32px rgba(0,0,0,0.4);z-index:250;padding:12px 14px;font-size:12px;animation:slideIn 0.2s cubic-bezier(0.16, 1, 0.3, 1);`,
  });

  const header = el(
    "div",
    { style: "display:flex;align-items:center;gap:8px;margin-bottom:8px;" },
    [
      el("span", { style: "font-size:14px;" }, "🤖"),
      el("div", { style: "flex:1;font-weight:600;color:var(--text-1);" }, "Bulk AI analysis"),
      el(
        "button",
        {
          class: "icon-btn",
          title: "Cancel & close",
          onclick: async () => {
            // Try the new orchestrator's cancel endpoint first (current default
            // path). Fall back to the legacy bulk-lead-analysis cancel for
            // older callers that haven't migrated yet.
            try {
              await api("crm-enrich-then-analyze-cancel", { jobId: initial.id });
            } catch {
              try {
                await api("crm-lead-analysis-bulk-cancel", { jobId: initial.id });
              } catch {}
            }
            isOpen = false;
            card.remove();
          },
        },
        "×",
      ),
    ],
  );
  card.appendChild(header);

  const progressLine = el(
    "div",
    { class: "muted small mono", style: "margin-bottom:6px;" },
    "Starting…",
  );
  card.appendChild(progressLine);

  // Progress bar.
  const barWrap = el("div", {
    style: "height:4px;background:var(--bg-3);border-radius:2px;overflow:hidden;margin-bottom:8px;",
  });
  const barFill = el("div", {
    style: "height:100%;background:var(--accent);width:0%;transition:width 200ms linear;",
  });
  barWrap.appendChild(barFill);
  card.appendChild(barWrap);

  // Verdict counters.
  const counters = el("div", {
    style: "display:grid;grid-template-columns:repeat(4,1fr);gap:6px;",
  });
  card.appendChild(counters);

  document.body.appendChild(card);

  function update(snapshot) {
    if (!isOpen) return;
    // Phase-aware rendering: orchestrator snapshots have shape
    //   { phase: "enriching"|"analyzing"|"done", enrich: {...}, analyze: {...} }
    // Legacy bulk-lead-analysis snapshots have flat counters at the top
    //   { processed, total, qualified, marginal, not_a_lead, failed, status }
    // We accept both so the widget works during the migration window.
    const isPhased = "phase" in snapshot;
    const total = snapshot.total || 0;
    let pct = 0;
    let line = "";

    if (isPhased) {
      const e = snapshot.enrich || {};
      const a = snapshot.analyze || {};
      if (snapshot.phase === "enriching") {
        // Enrich phase: bar tracks enrich percent so the user sees progress
        // even before the analyzer kicks in.
        pct = e.percent || 0;
        line = `Phase 1/2: Enriching · ${e.completed || 0}/${e.total_tasks || 0} tasks · ${pct}%${e.skipped_entities > 0 ? ` (${e.skipped_entities} pre-enriched)` : ""}`;
      } else if (snapshot.phase === "analyzing") {
        // Analyze phase: bar tracks analyze percent; show enrich summary
        // tucked into the line so the user sees both pieces of work done.
        pct = a.percent || 0;
        const enrichSummary =
          e.total_tasks > 0
            ? `enriched ${e.completed || 0}/${e.total_tasks}${e.timed_out ? " (timeout)" : ""}`
            : e.skipped_entities > 0
              ? `${e.skipped_entities} pre-enriched`
              : "skipped enrich";
        line = `Phase 2/2: Analyzing · ${a.processed || 0}/${total} · ${pct}% · ${enrichSummary}`;
      } else {
        // done / cancelled
        pct = 100;
        line =
          snapshot.status === "cancelled"
            ? `${a.processed || 0}/${total} · cancelled`
            : `${a.processed || 0}/${total} · done`;
      }
    } else {
      // Legacy snapshot path
      const processed = snapshot.processed || 0;
      pct = total > 0 ? Math.round((processed / total) * 100) : 0;
      line = snapshot._error
        ? `${processed}/${total} · polling: ${snapshot._error}`
        : snapshot.status === "running"
          ? `${processed}/${total} · ${pct}% · running…`
          : snapshot.status === "cancelled"
            ? `${processed}/${total} · cancelled`
            : `${processed}/${total} · done`;
    }

    barFill.style.width = `${pct}%`;
    progressLine.textContent = line;
    if (snapshot._error) {
      progressLine.style.color = "var(--yellow)";
    } else if (snapshot.status === "cancelled") {
      progressLine.style.color = "var(--yellow)";
      barFill.style.background = "var(--yellow)";
    } else if (snapshot.status === "running") {
      progressLine.style.color = "";
      barFill.style.background = "var(--accent)";
    } else {
      progressLine.style.color = "var(--green)";
      barFill.style.background = "var(--green)";
    }

    // Verdict counters (analyze phase). Read from either shape.
    const a = isPhased ? snapshot.analyze || {} : snapshot;
    counters.innerHTML = "";
    counters.appendChild(_counterCell("🟢", a.qualified || 0, "var(--green)"));
    counters.appendChild(_counterCell("🟡", a.marginal || 0, "var(--yellow)"));
    counters.appendChild(_counterCell("🔴", a.not_a_lead || 0, "var(--red)"));
    counters.appendChild(
      _counterCell("⚠", (a.failed != null ? a.failed : snapshot.failed) || 0, "var(--text-3)"),
    );
  }

  update(initial);

  return {
    update,
    isOpen: () => isOpen,
    close: () => {
      isOpen = false;
      card.remove();
    },
  };
}

function _counterCell(icon, n, color) {
  return el(
    "div",
    { style: `text-align:center;padding:4px 2px;background:var(--bg-2);border-radius:4px;` },
    [
      el("div", { style: "font-size:14px;" }, icon),
      el(
        "div",
        { class: "mono", style: `font-size:13px;font-weight:700;color:${color};` },
        String(n),
      ),
    ],
  );
}
