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

// ─────────────────────────────────────────────────────────────────
//
// The All tab merges LinkedIn rows + Telegram broadcasts into a single
// timestamp-sorted feed using the normalized row shape:
//   { id, platform, ts, action, status, target, detail, source, raw }
//
// The Telegram tab uses the same renderer with telegram-only data so
// LinkedIn-tab specialization (rich drawer + replay button) stays
// untouched. New platform adapters slot in by adding a normalizer.

function _normalizeLinkedInActionRow(row) {
  return {
    id: `li:${row.id}`,
    platform: "linkedin",
    ts: row.created_at,
    action: row.action || "—",
    status: row.status || "—",
    target: row.account_identifier || "—",
    detail:
      row.error_message ||
      (row.result_json ? _summarizeRow(row.result_json) || "" : "") ||
      (row.duration_ms != null ? `${row.duration_ms}ms` : ""),
    source: row.source || "linkedin",
    raw: row,
  };
}

function _normalizeTgBroadcastRow(b) {
  // Telegram broadcasts are aggregate events ("X sent to N groups").
  // Map status: completed→ok, sending→pending, failed→fail.
  const status =
    b.status === "completed"
      ? "ok"
      : b.status === "sending"
        ? "pending"
        : b.status === "failed"
          ? "fail"
          : b.status || "—";
  const detail = `${b.sent_count || 0} sent${b.failed_count ? ` · ${b.failed_count} failed` : ""}`;
  const target = (() => {
    if (Array.isArray(b.target_chat_ids)) return `${b.target_chat_ids.length} groups`;
    if (typeof b.target_chat_ids === "string")
      return `${b.target_chat_ids.split(",").length} groups`;
    return "—";
  })();
  return {
    id: `tg:bc:${b.id}`,
    platform: "telegram",
    ts: b.last_sent_at || b.created_at,
    action: "broadcast",
    status,
    target,
    detail:
      detail +
      (b.message_text
        ? ` · "${b.message_text.slice(0, 50)}${b.message_text.length > 50 ? "…" : ""}"`
        : ""),
    source: "tg-broadcast",
    raw: b,
  };
}

// Renders any normalized row. Click handler dispatches to platform-
// specific detail surface (LI rows open the rich drawer; TG rows open
// a simpler info modal).
function _renderUnifiedActivityRow(row) {
  const ts = row.ts ? new Date(row.ts) : null;
  const time =
    ts && !isNaN(ts)
      ? ts.toLocaleString([], {
          month: "short",
          day: "numeric",
          hour: "2-digit",
          minute: "2-digit",
        })
      : "—";
  const platformBadge = {
    linkedin: { label: "LI", bg: "#1a2a3a", color: "#93c5fd" },
    telegram: { label: "TG", bg: "#2a1a3a", color: "#c4b5fd" },
    x: { label: "X", bg: "#0f0f15", color: "#aaa" },
    gmail: { label: "GM", bg: "#3a2a1a", color: "#fbbf24" },
  }[row.platform] || { label: row.platform || "?", bg: "#222", color: "#aaa" };

  const statusIcon =
    row.status === "ok"
      ? "🟢"
      : row.status === "fail"
        ? "🔴"
        : row.status === "skip"
          ? "⚪"
          : row.status === "pending"
            ? "🟠"
            : "🟡";

  return el(
    "div",
    {
      class: "unified-activity-row",
      style:
        "display:flex;align-items:center;gap:10px;padding:8px 12px;border-bottom:1px solid #1a1a22;font-size:12px;cursor:pointer;transition:background 120ms;",
      onmouseenter: (e) => {
        e.currentTarget.style.background = "#1a1a22";
      },
      onmouseleave: (e) => {
        e.currentTarget.style.background = "transparent";
      },
      onclick: () => {
        if (row.platform === "linkedin" && row.raw) {
          _openLinkedInActivityDrawer(row.raw);
        } else {
          _openUnifiedActivityDrawer(row);
        }
      },
    },
    [
      el(
        "span",
        {
          style: `background:${platformBadge.bg};color:${platformBadge.color};font-size:9px;padding:2px 6px;border-radius:4px;font-family:monospace;font-weight:600;letter-spacing:0.4px;flex-shrink:0;width:24px;text-align:center;`,
        },
        platformBadge.label,
      ),
      el("span", { style: "color:#888;font-family:monospace;flex-shrink:0;width:110px;" }, time),
      el("span", { style: "flex-shrink:0;" }, statusIcon),
      el(
        "span",
        { style: "color:#fff;font-weight:500;flex-shrink:0;min-width:120px;" },
        row.action,
      ),
      el(
        "span",
        {
          style:
            "color:#888;font-family:monospace;font-size:10px;text-transform:uppercase;flex-shrink:0;",
        },
        row.status,
      ),
      el(
        "span",
        {
          style:
            "color:#aaa;flex-shrink:0;min-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",
        },
        row.target,
      ),
      el(
        "span",
        {
          style:
            "color:#666;font-size:11px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",
        },
        row.detail || "",
      ),
      row.link
        ? el(
            "a",
            {
              href: row.link,
              target: "_blank",
              rel: "noopener noreferrer",
              title: row.link,
              style: "flex-shrink:0;text-decoration:none;color:#6ea8ff;",
              onclick: (e) => e.stopPropagation(),
            },
            "🔗",
          )
        : null,
    ],
  );
}

// Simple detail drawer for non-LinkedIn rows. LinkedIn rows get the
// richer existing _openLinkedInActivityDrawer.
function _openUnifiedActivityDrawer(row) {
  const $drawerTitle = document.getElementById("drawer-title");
  const $drawerBody = document.getElementById("drawer-body");
  if (!$drawerTitle || !$drawerBody) return;
  $drawerTitle.textContent = `${row.action} — ${row.platform.toUpperCase()}`;
  $drawerBody.innerHTML = "";

  const fields = [
    ["Platform", row.platform],
    ["Time", row.ts || "—"],
    ["Action", row.action],
    ["Status", row.status],
    ["Target", row.target || "—"],
    ["Source", row.source || "—"],
    ["Detail", row.detail || "—"],
    ["Link", row.link || "—"],
  ];
  const dl = el("dl", { class: "li-activity-drawer-dl" });
  for (const [k, v] of fields) {
    dl.appendChild(el("dt", {}, k));
    dl.appendChild(el("dd", {}, String(v)));
  }
  $drawerBody.appendChild(dl);

  if (row.raw) {
    $drawerBody.appendChild(el("h4", {}, "Raw"));
    $drawerBody.appendChild(
      el("pre", { class: "li-activity-drawer-pre" }, _prettyJson(JSON.stringify(row.raw))),
    );
  }

  openDrawer();
}

// Telegram-only feed for the Action log Telegram tab.
async function _buildTgActivityBody(root) {
  root.appendChild(
    el(
      "div",
      { class: "muted", style: "padding:12px 0 16px;font-size:12px;" },
      "Telegram broadcast events. Invite job / forward / active-member event streams arrive once their per-action logs are exposed.",
    ),
  );

  const resp = await api("tg-broadcast-history").catch(() => null);
  const broadcasts = (resp?.broadcasts || []).slice(0, 50);

  if (broadcasts.length === 0) {
    root.appendChild(
      el("div", { class: "empty-state", style: "padding:32px;text-align:center;" }, [
        el("div", { style: "font-size:32px;margin-bottom:8px;" }, "📭"),
        el(
          "div",
          { style: "color:#aaa;font-size:13px;margin-bottom:6px;" },
          "No Telegram broadcasts yet",
        ),
        el(
          "div",
          { class: "muted", style: "font-size:12px;" },
          "Send one via Automations → Telegram → Broadcasts.",
        ),
      ]),
    );
    return;
  }

  const feed = el("div", {
    class: "unified-activity-feed",
    style: "background:#13131a;border:1px solid #2a2a38;border-radius:8px;overflow:hidden;",
  });
  for (const b of broadcasts) {
    feed.appendChild(_renderUnifiedActivityRow(_normalizeTgBroadcastRow(b)));
  }
  root.appendChild(feed);
}

// Unified "All" tab — powered by ONE server endpoint (/api/activity/feed) that
// merges every platform's action/event log into one time-sorted feed with
// clickable links. 5s dedup-polling (id-keyed; robust to the DB's mixed
// timestamp formats, so no fragile `since` comparison).
let _allActivityPollTimer = null;
let _allActivityShownIds = null;
function _stopAllActivityPoll() {
  if (_allActivityPollTimer) {
    clearInterval(_allActivityPollTimer);
    _allActivityPollTimer = null;
  }
}

function _renderAllActivityStrip(stripMount, counts, total) {
  stripMount.innerHTML = "";
  stripMount.appendChild(
    el(
      "div",
      {
        style:
          "display:flex;gap:12px;flex-wrap:wrap;padding:8px 12px;margin-bottom:8px;background:#1a1a22;border:1px solid #2a2a38;border-radius:6px;font-size:11px;color:#888;",
      },
      [
        el("span", {}, `${total} shown`),
        ...Object.entries(counts)
          .sort((a, b) => b[1] - a[1])
          .map(([p, n]) => el("span", {}, `• ${p} ${n}`)),
      ],
    ),
  );
}

// Cross-platform stats header — fed by /api/stats/overview. Resilient: if the
// endpoint isn't deployed yet it just renders nothing.
async function _renderAllStatsHeader(mount, days = 7) {
  const res = await api("stats-overview", { queryString: `?days=${days}` }).catch(() => null);
  if (!res || res.error || !res.activity) return;
  const a = res.activity;
  const totals = a.totals || { ok: 0, fail: 0, skip: 0 };
  const tile = (txt, color) =>
    el(
      "span",
      {
        style: `background:#13131a;border:1px solid #2a2a38;border-radius:6px;padding:4px 10px;font-size:12px;color:${color || "#ccc"};`,
      },
      txt,
    );
  mount.innerHTML = "";
  mount.appendChild(
    el("div", { style: "display:flex;gap:8px;flex-wrap:wrap;align-items:center;" }, [
      el(
        "span",
        { style: "font-size:11px;color:#777;margin-right:2px;" },
        `Last ${a.windowDays || days}d:`,
      ),
      tile(`🟢 ${totals.ok}`, "#5fdc8f"),
      tile(`🔴 ${totals.fail}`, "#ff8b8b"),
      tile(`⚪ ${totals.skip}`, "#aaa"),
      ...Object.entries(a.byPlatform || {}).map(([p, s]) =>
        el(
          "span",
          { style: "font-size:11px;color:#888;" },
          `${p}: ${s.ok || 0} ok / ${s.fail || 0} fail`,
        ),
      ),
    ]),
  );
  const fn = res.funnel?.funnel;
  if (fn) {
    mount.appendChild(
      el("div", { style: "display:flex;gap:10px;margin-top:6px;font-size:11px;color:#888;" }, [
        el("span", {}, `sent ${fn.sent || 0}`),
        el("span", {}, `→ replied ${fn.replied || 0}`),
        el("span", {}, `→ converted ${fn.converted || 0}`),
      ]),
    );
  }
}

async function _buildAllActivityBody(root) {
  _stopAllActivityPoll();
  _allActivityShownIds = new Set();
  root.appendChild(
    el(
      "div",
      { class: "muted", style: "padding:12px 0 16px;font-size:12px;" },
      "Unified action log — every action across X, LinkedIn, Telegram, Email & Luma, merged by time. Click 🔗 to open the post/message, or a row for details.",
    ),
  );

  const headerMount = el("div", { id: "all-activity-header", style: "margin-bottom:10px;" });
  root.appendChild(headerMount);
  _renderAllStatsHeader(headerMount).catch(() => {});

  const stripMount = el("div");
  root.appendChild(stripMount);
  const feed = el("div", {
    class: "unified-activity-feed",
    style: "background:#13131a;border:1px solid #2a2a38;border-radius:8px;overflow:hidden;",
  });
  const loadingEl = el(
    "div",
    { class: "muted", style: "padding:14px;text-align:center;" },
    "Loading unified feed…",
  );
  root.appendChild(loadingEl);
  root.appendChild(feed);

  const res = await api("activity-feed", { queryString: "?limit=120" }).catch((e) => ({
    error: e.message,
  }));
  loadingEl.remove();
  if (res?.error) {
    feed.appendChild(
      el(
        "div",
        { class: "muted", style: "padding:24px;text-align:center;" },
        `Couldn't load feed: ${res.error}`,
      ),
    );
    return;
  }
  const rows = res?.rows || [];
  const counts = {};
  if (rows.length === 0) {
    feed.appendChild(
      el("div", { class: "empty-state", style: "padding:32px;text-align:center;" }, [
        el("div", { style: "font-size:32px;margin-bottom:8px;" }, "📭"),
        el(
          "div",
          { style: "color:#aaa;font-size:13px;margin-bottom:6px;" },
          "No actions recorded yet",
        ),
        el(
          "div",
          { class: "muted", style: "font-size:12px;" },
          "Run an automation from any platform — events stream here as they happen.",
        ),
      ]),
    );
  } else {
    for (const row of rows) {
      _allActivityShownIds.add(row.id);
      counts[row.platform] = (counts[row.platform] || 0) + 1;
      feed.appendChild(_renderUnifiedActivityRow(row));
    }
    _renderAllActivityStrip(stripMount, counts, rows.length);
  }

  // Incremental dedup-polling: re-fetch top 50, prepend genuinely-new rows.
  _allActivityPollTimer = setInterval(async () => {
    if (!String(location.hash).includes("action-log")) {
      _stopAllActivityPoll();
      return;
    }
    const r = await api("activity-feed", { queryString: "?limit=50" }).catch(() => null);
    const fresh = (r?.rows || []).filter((row) => !_allActivityShownIds.has(row.id));
    if (!fresh.length) return;
    for (const row of fresh.reverse()) {
      _allActivityShownIds.add(row.id);
      counts[row.platform] = (counts[row.platform] || 0) + 1;
      feed.insertBefore(_renderUnifiedActivityRow(row), feed.firstChild);
    }
    _renderAllActivityStrip(stripMount, counts, _allActivityShownIds.size);
  }, 5000);
}

// Body builder shared between the legacy standalone page (above) and
// the LinkedIn tab inside renderActivityHub. Takes a parent node and
// appends the full LinkedIn activity feed UI to it. `routeName` lets
// the poller know which route to watch for navigation-away (the hub
// uses "action-log").
async function _buildLiActivityBody(root, { routeName } = {}) {
  _stopLinkedInActivityPoll();
  _liActivityLastId = 0;
  _liActivityRows = [];

  const headerMount = el("div", { id: "li-activity-header-mount" }, [
    el("div", { class: "muted" }, "Loading status…"),
  ]);
  const filtersMount = _renderLinkedInActivityFilters();
  const feed = el("div", { id: "li-activity-feed", class: "li-activity-feed" });
  root.appendChild(headerMount);
  root.appendChild(filtersMount);
  root.appendChild(feed);

  // Initial full refresh, then 5s incremental polling while view is active.
  await _refreshLinkedInActivity({ full: true });
  const watchRoute = routeName || "linkedin/activity";
  _liActivityPollTimer = setInterval(() => {
    // Stop if user navigated away — handleRoute hasn't called stop yet.
    if (dashboardState.currentRoute !== watchRoute) {
      _stopLinkedInActivityPoll();
      return;
    }
    _refreshLinkedInActivity({ full: false }).catch(() => {
      /* ignore one-cycle failures */
    });
  }, 5000);
}
