// dashboard-liautoonunmount.js — extracted verbatim from dashboard.js (pure move).

// ─────────────────────────────────────────────────────────────────
//
// Card grid + modal config form + live progress drawer. Schema lives
// in window.LI_ACTION_REGISTRY (linkedin-action-registry.js).
//
// Flow:
//   1. User opens #linkedin/automations
//   2. Renderer fetches /api/linkedin/budget once + polls worker-tab
//      status every 3s
//   3. Each card shows: title, hint, today's budget pill, "Run" button
//   4. Click Run → modal opens with schema-driven inputs
//   5. Submit → sends the action's swAction message to background.js,
//      includes panelTabId=<dashboard tab id> so progress messages
//      route back here
//   6. Progress drawer opens; nx-batch-progress messages stream into
//      its log list. On done, drawer offers "View in Activity" link
//      to #linkedin/activity.

let _liAutoUnloadHandlers = [];
let _liAutoStatusPoll = null;
let _liAutoBatchListener = null;

function _liAutoOnUnmount(fn) {
  _liAutoUnloadHandlers.push(fn);
}
function _liAutoRunUnmount() {
  for (const fn of _liAutoUnloadHandlers) {
    try {
      fn();
    } catch {
      /* ignore */
    }
  }
  _liAutoUnloadHandlers = [];
}

async function renderLinkedInAutomations() {
  // Legacy entry — kept so #linkedin/automations deep links still work
  // until the redirect catches them. Identical to the LinkedIn tab
  // inside #automations.
  const root = el("div", { class: "li-auto-view", style: "padding: 16px;" });
  setContentNode(root);
  await _buildLiAutomationsBody(root);
}

// Body builder shared between the legacy standalone page (above) and
// the LinkedIn tab inside renderAutomationsHub. Takes a parent node
// and appends the full LinkedIn Automations UI (header + budget pills +
// card grid + progress drawer + worker-status poll + batch listener).
async function _buildLiAutomationsBody(root) {
  _liAutoRunUnmount();

  // Header strip: title + worker pill + active-batch banner
  const headerWorkerPill = el(
    "span",
    {
      class: "pill",
      id: "li-auto-worker-pill",
      style:
        "background:var(--border-soft);color:#999;padding:4px 10px;border-radius:8px;font-size:11px;",
    },
    "worker: …",
  );
  const headerPanelLink = el(
    "a",
    { href: "#action-log/linkedin", class: "btn btn-secondary btn-xs", style: "margin-left:auto;" },
    "Action log →",
  );
  const header = el(
    "div",
    { class: "page-header", style: "display:flex;align-items:center;gap:12px;margin-bottom:16px;" },
    [
      el("div", {}, [
        el("h2", { style: "margin:0;font-size:16px;color:var(--text-1);" }, "LinkedIn"),
        el(
          "p",
          { class: "muted", style: "margin:4px 0 0;font-size:12px;" },
          "Every action runs in a hidden background Chrome window. Your current tab is never touched.",
        ),
      ]),
      headerWorkerPill,
      headerPanelLink,
    ],
  );
  root.appendChild(header);

  // Status panel — fetched once. Tells the user about account-wall
  // cooldown if one's active (which would gray out every card).
  const wallBanner = el("div", { id: "li-auto-wall-banner" });
  root.appendChild(wallBanner);

  // Card grid container — populated below once budget loads.
  const gridMount = el("div", {
    class: "li-auto-grid",
    id: "li-auto-grid",
    style: "display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:14px;",
  });
  root.appendChild(gridMount);

  // Progress drawer (hidden by default; shown when a batch starts).
  const drawer = el("div", {
    id: "li-auto-drawer",
    style:
      "display:none;position:fixed;bottom:16px;right:16px;width:420px;max-height:60vh;background:var(--bg-card);border:1px solid var(--border-soft);border-radius:10px;box-shadow:0 12px 36px rgba(0,0,0,0.5);z-index:1500;overflow:hidden;display:flex;flex-direction:column;",
  });
  root.appendChild(drawer);

  // ── Status pill poll (every 3s) ───────────────────────────────
  async function refreshWorkerPill() {
    try {
      const t = await new Promise((resolve) => {
        chrome.runtime.sendMessage({ action: "li-worker-tab-status" }, (r) => {
          if (chrome.runtime.lastError) resolve(null);
          else resolve(r);
        });
      });
      if (t?.exists) {
        headerWorkerPill.textContent = `worker: running · ${(t.url || "").replace("https://www.linkedin.com", "").slice(0, 30)}`;
        headerWorkerPill.style.background = "#1a3a1a";
        headerWorkerPill.style.color = "var(--green)";
      } else {
        headerWorkerPill.textContent = "worker: idle";
        headerWorkerPill.style.background = "var(--border-soft)";
        headerWorkerPill.style.color = "var(--text-3)";
      }
    } catch {
      /* keep the previous state */
    }
  }
  refreshWorkerPill();
  _liAutoStatusPoll = setInterval(refreshWorkerPill, 3000);
  _liAutoOnUnmount(() => {
    clearInterval(_liAutoStatusPoll);
    _liAutoStatusPoll = null;
  });

  // ── Budget fetch + render the cards ────────────────────────────
  const budget = await api("li-budget").catch(() => ({}));

  // Account-wall banner — if any category came back with the cooldown,
  // surface it at the top. Cards are still rendered but all disabled.
  const wallEntry = Object.values(budget || {}).find(
    (b) => b && b.blockedReason && b.blockedReason.startsWith("account_wall_cooldown"),
  );
  let accountWallActive = false;
  if (wallEntry) {
    accountWallActive = true;
    wallBanner.appendChild(
      el(
        "div",
        {
          style:
            "background:#3a1a1a;border:1px solid #5a2a2a;color:var(--red);padding:10px 14px;border-radius:8px;margin-bottom:14px;font-size:13px;",
        },
        [
          el("b", {}, "Account wall active. "),
          el(
            "span",
            {},
            wallEntry.blockedReason +
              " — all LinkedIn automation is paused. Resolve via Telegram /liresolve <id>.",
          ),
        ],
      ),
    );
  }

  const registry = window.LI_ACTION_REGISTRY || [];
  if (registry.length === 0) {
    gridMount.appendChild(
      el("div", { class: "muted" }, "Action registry not loaded — reload extension."),
    );
    return;
  }

  for (const action of registry) {
    gridMount.appendChild(_renderLiAutoCard(action, budget, accountWallActive));
  }

  // Set up the per-page nx-batch-progress listener once for the
  // dashboard tab. Routed by background.js when a batch we started
  // emits a progress message.
  _setupDashboardBatchListener();
}

function _renderLiAutoCard(action, budget, accountWallActive) {
  const catBudget = budget?.[action.limitsCategory] || null;
  const remaining = catBudget?.remainingToday;
  const dailyLimit = catBudget?.dailyLimit;
  const ageMult = catBudget?.accountAgeMultiplier;

  const card = el("div", {
    class: "card li-auto-card",
    style:
      "background:var(--bg-card);border:1px solid var(--border-soft);border-radius:10px;padding:14px;display:flex;flex-direction:column;gap:10px;",
  });
  // Title row + budget pill
  const budgetPill = el(
    "span",
    {
      style:
        "font-size:10px;background:var(--bg-1);color:var(--text-3);padding:3px 8px;border-radius:6px;font-family:monospace;",
    },
    catBudget
      ? catBudget.allowed
        ? `${remaining}/${dailyLimit} today`
        : catBudget.blockedReason?.split(":")[0] || "blocked"
      : "—",
  );
  if (!catBudget?.allowed && catBudget) {
    budgetPill.style.background = "#3a1a1a";
    budgetPill.style.color = "var(--red)";
  } else if (catBudget?.allowed && remaining > 0) {
    budgetPill.style.color = "var(--green)";
  }
  const titleRow = el("div", { style: "display:flex;align-items:center;gap:8px;" }, [
    el("h3", { style: "margin:0;font-size:14px;color:var(--text-1);flex:1;" }, action.title),
    budgetPill,
  ]);
  card.appendChild(titleRow);

  card.appendChild(
    el("div", { class: "muted", style: "font-size:12px;line-height:1.5;color:#999;" }, action.hint),
  );

  if (ageMult != null && ageMult < 1.0) {
    card.appendChild(
      el(
        "div",
        { style: "font-size:11px;color:#fbbf24;" },
        `Warmup multiplier: x${ageMult.toFixed(1)} (account age)`,
      ),
    );
  }

  // Run button — disabled if budget exhausted or account-wall active.
  const blocked = accountWallActive || (catBudget && !catBudget.allowed);
  const btn = el(
    "button",
    {
      class: "btn btn-primary",
      style: "margin-top:6px;" + (blocked ? "opacity:0.5;cursor:not-allowed;" : ""),
      disabled: blocked ? "" : null,
      onclick: blocked ? null : () => openAutomationDetail({ type: "li_action", action }),
    },
    blocked ? (accountWallActive ? "Paused — account wall" : "Out of budget") : "View & run",
  );
  card.appendChild(btn);
  return card;
}

function _openLiAutoConfigModal(action, prefill) {
  // Migrated to the shared openModal (Esc + focus-trap + focus-restore + aria).
  const _h = {};
  const pf = prefill || {}; // preserve raw values when returning from Preview
  const formEl = el("form", {
    style: "display:flex;flex-direction:column;gap:10px;",
    onsubmit: (e) => e.preventDefault(),
  });
  formEl.appendChild(
    el("p", { class: "muted", style: "margin:0 0 8px;font-size:12px;" }, action.hint),
  );
  const inputs = {};
  for (const field of action.fields) {
    const row = el("div", {});
    if (field.type !== "boolean") {
      row.appendChild(
        el(
          "label",
          { style: "display:block;font-size:11px;color:var(--text-3);margin-bottom:4px;" },
          field.label,
        ),
      );
    }
    let input;
    const pfVal = pf[field.id];
    if (field.type === "textarea") {
      input = el(
        "textarea",
        {
          rows: "3",
          placeholder: field.placeholder || "",
          style:
            "width:100%;background:var(--bg-1);border:1px solid var(--border-soft);color:var(--text-1);border-radius:6px;padding:8px;font-size:12px;font-family:inherit;",
        },
        (pfVal ?? field.default) || "",
      );
      if (field.chips) {
        const chips = el("div", {
          style: "display:flex;gap:4px;flex-wrap:wrap;margin-bottom:6px;",
        });
        for (const chip of field.chips) {
          chips.appendChild(
            el(
              "span",
              {
                style:
                  "background:var(--border-soft);color:var(--text-2);padding:2px 6px;border-radius:4px;font-size:10px;font-family:monospace;cursor:pointer;",
                onclick: () => {
                  input.value = (input.value || "") + chip;
                  input.focus();
                },
              },
              chip,
            ),
          );
        }
        row.appendChild(chips);
      }
    } else if (field.type === "boolean") {
      input = el("input", { type: "checkbox" });
      input.checked = pfVal != null ? !!pfVal : !!field.default;
      const checkLabel = el("label", {
        style: "display:flex;align-items:center;gap:8px;font-size:12px;color:var(--text-1);",
      });
      checkLabel.appendChild(input);
      checkLabel.appendChild(document.createTextNode(field.label));
      row.appendChild(checkLabel);
    } else if (field.type === "number") {
      input = el("input", {
        type: "number",
        value: String(pfVal ?? field.default ?? ""),
        min: field.min != null ? String(field.min) : null,
        max: field.max != null ? String(field.max) : null,
        style:
          "width:100px;background:var(--bg-1);border:1px solid var(--border-soft);color:var(--text-1);border-radius:6px;padding:6px 8px;font-size:12px;",
      });
    } else {
      // text
      input = el("input", {
        type: "text",
        value: String(pfVal ?? field.default ?? ""),
        placeholder: field.placeholder || "",
        style:
          "width:100%;background:var(--bg-1);border:1px solid var(--border-soft);color:var(--text-1);border-radius:6px;padding:6px 8px;font-size:12px;",
      });
    }
    if (field.type !== "boolean") row.appendChild(input);
    if (field.hint)
      row.appendChild(
        el(
          "div",
          { class: "muted", style: "font-size:11px;margin-top:3px;color:var(--text-4);" },
          field.hint,
        ),
      );
    formEl.appendChild(row);
    inputs[field.id] = input;
  }

  // Read + validate the form into raw values (null on validation fail).
  const collectRaw = () => {
    const raw = {};
    for (const [id, inp] of Object.entries(inputs)) {
      raw[id] = inp.type === "checkbox" ? inp.checked : inp.value;
    }
    const templateField = action.fields.find((f) => f.id === "template");
    if (templateField && (!raw.template || !raw.template.trim())) {
      toast("Template required", "err");
      return null;
    }
    return raw;
  };
  const cancelBtn = el(
    "button",
    {
      class: "btn btn-secondary",
      onclick: () => {
        if (_h.close) _h.close();
      },
    },
    "Cancel",
  );
  // Preview: plain-English step map with your inputs — nothing runs.
  const previewBtn = el(
    "button",
    {
      class: "btn btn-secondary",
      title: "See exactly what this will do — nothing runs",
      onclick: () => {
        const raw = collectRaw();
        if (!raw) return;
        if (_h.close) _h.close();
        _openLiPreviewModal(action, raw);
      },
    },
    "Preview",
  );
  const startBtn = el(
    "button",
    {
      class: "btn btn-primary",
      onclick: async () => {
        const raw = collectRaw();
        if (!raw) return;
        const config = action.configTransform ? action.configTransform(raw) : raw;
        if (_h.close) _h.close();
        await _liAutoStartBatch(action, config);
      },
    },
    "Start batch",
  );

  const h = openModal({
    title: action.title,
    body: formEl,
    actions: [cancelBtn, previewBtn, startBtn],
    maxWidth: "520px",
  });
  _h.close = h.close;
}

// Preview modal for LinkedIn batch actions — mirrors _openXPreviewModal. Shows
// the resolved (clamped/normalized) settings + the plain-English step map, with
// no execution. "Edit inputs" returns to the form with values preserved.
function _openLiPreviewModal(action, raw) {
  const fields = action.fields || [];
  const nodes = (action.moduleMap && action.moduleMap.nodes) || [];
  const config = action.configTransform ? action.configTransform(raw) : raw;
  const fieldById = {};
  for (const f of fields) fieldById[f.id] = f;

  const body = el("div", { style: "display:flex;flex-direction:column;gap:14px;" });
  body.appendChild(
    el(
      "div",
      {
        style:
          "font-size:11px;color:#fbbf24;background:#1a1606;border:1px solid #3a3206;border-radius:6px;padding:8px 10px;line-height:1.5;",
      },
      "Preview only — nothing has run yet. When you click “Start batch”, here's exactly what happens, step by step:",
    ),
  );

  // Your settings — show the RAW values keyed by their field labels (what you typed).
  const shown = Object.entries(raw).filter(([, v]) => v !== "" && v != null);
  if (shown.length) {
    body.appendChild(
      el(
        "h3",
        {
          style:
            "margin:0;font-size:11px;color:var(--text-3);text-transform:uppercase;letter-spacing:0.6px;",
        },
        "Your settings",
      ),
    );
    const dl = el("div", { style: "display:flex;flex-direction:column;gap:4px;font-size:12px;" });
    for (const [id, v] of shown) {
      const label = (fieldById[id] && fieldById[id].label) || id;
      dl.appendChild(
        el("div", {}, [
          el("span", { style: "color:var(--text-3);" }, label + ": "),
          el(
            "span",
            { style: "color:var(--text-1);" },
            String(v === true ? "yes" : v === false ? "no" : v),
          ),
        ]),
      );
    }
    body.appendChild(dl);
  }

  body.appendChild(
    el(
      "h3",
      {
        style:
          "margin:0;font-size:11px;color:var(--text-3);text-transform:uppercase;letter-spacing:0.6px;",
      },
      `Steps (${nodes.length})`,
    ),
  );
  if (nodes.length) {
    const ol = el("ol", {
      style: "margin:0;padding-left:24px;font-size:13px;line-height:1.7;color:#ddd;",
    });
    for (const n of nodes) {
      const gloss = _stepGloss(n.type);
      ol.appendChild(
        el("li", { style: "margin-bottom:6px;" }, [
          el("span", { style: "color:#e8e8ef;" }, n.name || n.id),
          gloss ? el("span", { style: "color:#8a8a98;" }, ` — ${gloss}`) : null,
        ]),
      );
    }
    body.appendChild(ol);
  } else {
    body.appendChild(
      el(
        "p",
        { class: "muted", style: "font-size:12px;" },
        "No step map available for this action yet.",
      ),
    );
  }

  const _h = {};
  const editBtn = el(
    "button",
    {
      class: "btn btn-secondary",
      onclick: () => {
        if (_h.close) _h.close();
        _openLiAutoConfigModal(action, raw);
      },
    },
    "← Edit inputs",
  );
  const startBtn = el(
    "button",
    {
      class: "btn btn-primary",
      onclick: async () => {
        if (_h.close) _h.close();
        await _liAutoStartBatch(action, config);
      },
    },
    "Start batch →",
  );
  const h = openModal({
    title: `Preview · ${action.title}`,
    body,
    actions: [editBtn, startBtn],
    maxWidth: "520px",
  });
  _h.close = h.close;
}

async function _liAutoStartBatch(action, config) {
  // Correlation id so the worker tab's per-step screenshots attach to THIS run
  // (shared run-shots store; the 📸 Replay button reads it back).
  const runId = `li_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
  _liRunCurrentRunId = runId;
  _openLiAutoDrawer(action.title);
  _liAutoDrawerAppendLog("…", `Starting ${action.title}… (run ${runId})`);
  try {
    const result = await new Promise((resolve) => {
      chrome.runtime.sendMessage(
        {
          action: action.swAction,
          config,
          runId,
        },
        (r) => {
          if (chrome.runtime.lastError) resolve({ error: chrome.runtime.lastError.message });
          else resolve(r || { error: "no_response" });
        },
      );
    });
    if (result?.error) {
      _liAutoDrawerAppendLog("X", `Failed: ${result.error}`);
      toast(`Batch failed: ${result.error}`, "err");
    } else if (result?.accepted !== undefined || result?.messaged !== undefined) {
      const a = result.accepted ?? 0;
      const m = result.messaged ?? 0;
      _liAutoDrawerAppendLog("✓", `Done — ${a} accepted, ${m} messaged`);
      toast(`Batch done — ${a} accepted, ${m} messaged`, "ok", 6000, () =>
        navigate("linkedin/activity"),
      );
    } else {
      _liAutoDrawerAppendLog("✓", `Done`);
      toast("Batch completed", "ok", 4000, () => navigate("linkedin/activity"));
    }
  } catch (err) {
    _liAutoDrawerAppendLog("X", `Threw: ${err.message}`);
    toast(`Error: ${err.message}`, "err");
  }
}

function _openLiAutoDrawer(actionTitle) {
  const drawer = document.getElementById("li-auto-drawer");
  if (!drawer) return;
  drawer.innerHTML = "";
  drawer.style.display = "flex";
  const header = el(
    "div",
    {
      style:
        "padding:10px 14px;border-bottom:1px solid var(--border-soft);display:flex;align-items:center;gap:8px;",
    },
    [
      el("strong", { style: "color:var(--text-1);font-size:13px;flex:1;" }, actionTitle),
      el(
        "span",
        { id: "li-auto-drawer-status", class: "muted", style: "font-size:11px;" },
        "Running…",
      ),
      el(
        "button",
        {
          title: "Visual replay — screenshots of each step",
          style:
            "background:transparent;border:1px solid var(--border-soft);border-radius:5px;color:#a78bfa;font-size:11px;cursor:pointer;padding:2px 7px;",
          "aria-label": "Replay screenshots",
          onclick: () => _openRunReplayModal(_liRunCurrentRunId),
        },
        "Replay",
      ),
      el(
        "button",
        {
          style:
            "background:transparent;border:none;color:var(--text-3);font-size:18px;cursor:pointer;padding:0 4px;",
          "aria-label": "Close progress panel",
          onclick: () => {
            drawer.style.display = "none";
            drawer.innerHTML = "";
          },
        },
        "×",
      ),
    ],
  );
  drawer.appendChild(header);
  const logList = el("div", {
    id: "li-auto-drawer-log",
    style:
      "padding:8px 14px;flex:1;overflow-y:auto;font-size:12px;font-family:monospace;color:var(--text-2);",
  });
  drawer.appendChild(logList);
}

// Cap the drawer log at the most-recent N lines (matches _X_ACTIVITY_MAX_ROWS
// style). The list is scrollTop-pinned to the bottom on every append, so older
// lines are never on screen and trimming the head is not user-visible.
const _LI_AUTO_LOG_MAX = 500;
function _liAutoDrawerAppendLog(icon, text) {
  const log = document.getElementById("li-auto-drawer-log");
  if (!log) return;
  const line = el(
    "div",
    { style: "padding:3px 0;border-bottom:1px solid var(--bg-card);" },
    `${icon} ${text}`,
  );
  log.appendChild(line);
  while (log.childElementCount > _LI_AUTO_LOG_MAX) log.removeChild(log.firstChild);
  log.scrollTop = log.scrollHeight;
}

function _liAutoDrawerSetStatus(text) {
  const s = document.getElementById("li-auto-drawer-status");
  if (s) s.textContent = text;
}

function _setupDashboardBatchListener() {
  if (_liAutoBatchListener) {
    try {
      chrome.runtime.onMessage.removeListener(_liAutoBatchListener);
    } catch {}
  }
  _liAutoBatchListener = (msg) => {
    if (!msg || !msg.nexusPanel) return;
    if (msg.type === "log") _liAutoDrawerAppendLog(msg.data?.icon || "·", msg.data?.text || "");
    else if (msg.type === "status") _liAutoDrawerSetStatus(String(msg.data || "").slice(0, 60));
  };
  try {
    chrome.runtime.onMessage.addListener(_liAutoBatchListener);
  } catch {}
  _liAutoOnUnmount(() => {
    if (_liAutoBatchListener) {
      try {
        chrome.runtime.onMessage.removeListener(_liAutoBatchListener);
      } catch {}
      _liAutoBatchListener = null;
    }
  });
}
