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

// ── Notifications Inbox ─────────────────────────────────────────
//
// Surfaces things OTHER PEOPLE did to us. Backend (handleInboxReplies) merges:
//   - inbound outreach_events (reply_received, connect_accepted, dm_received,
//     notification_received) — strict allowlist, no outbound leaks
//   - inbox_messages WHERE direction='inbound' (DMs scraped from LI/TG/Email)
//   - linkedin_connection_requests WHERE status='pending' (someone wants to connect)
//
// Likes / follows / mentions received are not yet scraped — adding those
// requires platform notification scrapers (TODO).

const INBOX_EVENT_LABELS = {
  reply_received: { icon: "↩️", label: "Reply" },
  reply_detected: { icon: "↩️", label: "Reply" },
  connect_accepted: { icon: "🤝", label: "Connection accepted" },
  connection_request: { icon: "➕", label: "Wants to connect" },
  dm_received: { icon: "✉️", label: "DM" },
  message_received: { icon: "✉️", label: "Message" },
  notification_received: { icon: "🔔", label: "Notification" },
  inbound: { icon: "✉️", label: "Message" },
};

async function renderInbox() {
  showLoading("Loading notifications\u2026");
  // Shares the cache with refreshInboxBadge \u2014 if the badge tick just ran, this
  // hits cache and renders instantly. apiMutate("inbox-reply") busts the cache
  // when the user replies, so the list always shows the latest after sending.
  const data = await apiCached("inbox-replies").catch(() => ({}));
  if (data?.error) {
    showError(data.error, renderInbox);
    return;
  }
  const replies = data.replies || [];

  const platformIcons = {
    x: "\ud83d\udc26",
    twitter: "\ud83d\udc26",
    linkedin: "\ud83d\udd17",
    telegram: "\u2708\ufe0f",
    email: "\u2709\ufe0f",
  };

  const content = el("div", {}, [
    el("div", { class: "page-header" }, [
      el("div", {}, [
        el("div", { class: "page-title" }, "Notifications"),
        el(
          "div",
          { class: "page-subtitle" },
          `${replies.length} things people did toward you \u2014 replies, DMs, connection requests. Click a row to open the contact, or use the buttons to jump to the original.`,
        ),
      ]),
      el(
        "button",
        { class: "btn btn-secondary", type: "button", onclick: renderInbox },
        "\u21bb Refresh",
      ),
    ]),
    replies.length === 0
      ? el("div", { class: "empty-state" }, [
          el("div", { class: "empty-state-icon" }, "\ud83d\udcec"),
          el("div", { class: "empty-state-title" }, "No notifications yet"),
          el(
            "div",
            { class: "empty-state-hint" },
            "When someone replies to your outreach, sends a DM, or wants to connect, it'll show up here.",
          ),
        ])
      : el(
          "div",
          {},
          replies.map((r) => renderInboxCard(r)),
        ),
  ]);
  setContentNode(content);
}

// Channels we can reply to in-extension. Telegram now routes via the
// owner-bot's grammy api.sendMessage — but only if the recipient has
// previously started the bot (Telegram blocks cold-DMs from bots).
// On failure the API returns a fallbackUrl pointing to t.me.
const INBOX_REPLYABLE_PLATFORMS = new Set(["x", "twitter", "linkedin", "email", "telegram"]);

function renderInboxCard(r) {
  const platformIcons = { x: "🐦", twitter: "🐦", linkedin: "🔗", telegram: "✈️", email: "✉️" };
  const platformIcon = platformIcons[r.platform] || "•";
  const evt = INBOX_EVENT_LABELS[r.event_type] || { icon: "•", label: r.event_type || "" };
  const links = inboxRowLinks(r);
  const platform = String(r.platform || "").toLowerCase();
  const canReply = INBOX_REPLYABLE_PLATFORMS.has(platform) && r.id;

  // Container we can mutate when the user toggles the reply form.
  const card = el("div", {
    class: "card",
    style: "padding: 14px; margin-bottom: 8px; cursor: pointer;",
    onclick: (e) => {
      if (e.target.closest(".inbox-link-btn") || e.target.closest(".inbox-reply-area")) return;
      if (r.contact_id) showContactDrawer(r.contact_id);
    },
  });

  const replySlot = el("div", { class: "inbox-reply-area", style: "margin-top: 8px;" });

  card.appendChild(
    el("div", { style: "display: flex; align-items: center; gap: 8px; margin-bottom: 6px;" }, [
      el("span", { style: "font-size: 16px;", title: r.platform || "" }, platformIcon),
      el("span", { style: "font-size: 14px;", title: evt.label }, evt.icon),
      el("span", { class: "primary-cell" }, r.contact_name || "Unknown"),
      r.company ? el("span", { class: "muted small" }, `@ ${r.company}`) : null,
      el("span", { class: "badge badge-blue" }, evt.label),
      el(
        "span",
        {
          class: "muted",
          style: "margin-left: auto; font-size: 10px; font-family: var(--font-mono);",
        },
        fmtDate(r.created_at),
      ),
    ]),
  );
  card.appendChild(
    el(
      "div",
      { class: "muted", style: "font-size: 12px; line-height: 1.5; margin-bottom: 8px;" },
      (r.detail || evt.label || "").slice(0, 240) + ((r.detail || "").length > 240 ? "…" : ""),
    ),
  );

  // Action row: deep-links + (if supported) Reply button
  const actionRow = el("div", {
    style: "display: flex; flex-wrap: wrap; gap: 6px; align-items: center;",
  });
  for (const l of links) {
    actionRow.appendChild(
      el(
        "a",
        {
          class: "btn btn-tiny btn-secondary inbox-link-btn",
          href: l.href,
          target: "_blank",
          rel: "noopener noreferrer",
          title: l.title || l.label,
          onclick: (e) => e.stopPropagation(),
        },
        l.label,
      ),
    );
  }
  if (canReply) {
    actionRow.appendChild(
      el(
        "button",
        {
          class: "btn btn-tiny btn-primary inbox-link-btn",
          type: "button",
          onclick: (e) => {
            e.stopPropagation();
            // Toggle: if form is already open, collapse it. Otherwise mount.
            if (replySlot.firstChild) {
              replySlot.replaceChildren();
            } else {
              replySlot.appendChild(renderInboxReplyForm(r, replySlot));
            }
          },
        },
        `↩ Reply on ${platform === "twitter" ? "X" : platform}`,
      ),
    );
  }
  card.appendChild(actionRow);
  card.appendChild(replySlot);

  return card;
}

// Inline reply form mounted into the card. Calls /api/inbox/:id/reply.
// Per-platform character limit (X = 280 default, others have generous
// defaults). Cmd/Ctrl+Enter sends. Send button disabled when empty or
// over the limit so the user can't fire a guaranteed-to-fail request.
function renderInboxReplyForm(r, replySlot) {
  const platform = String(r.platform || "").toLowerCase();
  const recipientHint =
    {
      x: r.twitter_handle ? `@${r.twitter_handle}` : "this tweet",
      twitter: r.twitter_handle ? `@${r.twitter_handle}` : "this tweet",
      linkedin: r.contact_name || "this contact",
      email: r.email || "this contact",
      telegram: r.telegram_username ? `@${r.telegram_username}` : r.contact_name || "this contact",
    }[platform] || "this contact";

  // Effective char limit per channel. X = 280 (free tier), email/LI/TG
  // have soft limits we cap at 4000 for sanity.
  const charLimit = platform === "x" || platform === "twitter" ? 280 : 4000;

  let text = "";
  const counter = el(
    "span",
    {
      class: "muted small mono",
      style: "user-select: none;",
    },
    `0 / ${charLimit}`,
  );

  const errBox = el("div", {
    class: "muted small",
    style: "color: var(--red); margin-top: 6px; display: none;",
  });

  const sendBtn = el(
    "button",
    {
      class: "btn btn-tiny btn-primary",
      type: "button",
      disabled: "disabled",
      title: "Type a message first (Cmd/Ctrl+Enter to send)",
      onclick: async (ev) => {
        ev.stopPropagation();
        if (sendBtn.disabled) return;
        await sendReply(ev);
      },
    },
    "Send",
  );

  async function sendReply(ev) {
    if (!text.trim()) {
      errBox.textContent = "Type a message first";
      errBox.style.display = "block";
      return;
    }
    if (text.length > charLimit) {
      errBox.textContent = `Too long — ${text.length} / ${charLimit}. Trim before sending.`;
      errBox.style.display = "block";
      return;
    }
    errBox.style.display = "none";
    await withProgress(ev.currentTarget, async () => {
      // apiMutate auto-busts the cached inbox-replies so the badge / list refresh.
      const result = await apiMutate("inbox-reply", { eventId: r.id, body: { text } });
      if (result?.error) {
        errBox.textContent = result.error + (result.fallbackUrl ? ` — opening original` : "");
        errBox.style.display = "block";
        if (result.fallbackUrl) {
          setTimeout(() => chrome.tabs.create({ url: result.fallbackUrl }), 600);
        }
      } else {
        toast(`✅ Reply sent on ${result.channel}`, "ok");
        replySlot.replaceChildren();
        setTimeout(renderInbox, 400);
      }
    });
  }

  function updateCounter() {
    const len = text.length;
    counter.textContent = `${len} / ${charLimit}`;
    counter.style.color =
      len > charLimit ? "var(--red)" : len > charLimit * 0.9 ? "var(--yellow)" : "";
    sendBtn.disabled = len === 0 || len > charLimit ? "disabled" : null;
    if (sendBtn.disabled) {
      sendBtn.removeAttribute("disabled");
      sendBtn.setAttribute("disabled", "disabled");
    } else {
      sendBtn.removeAttribute("disabled");
    }
    sendBtn.title =
      len === 0
        ? "Type a message first (Cmd/Ctrl+Enter to send)"
        : len > charLimit
          ? `Too long — trim ${len - charLimit} chars`
          : "Send (Cmd/Ctrl+Enter)";
  }

  const textarea = el("textarea", {
    class: "wizard-textarea",
    style: "min-height: 70px;",
    placeholder:
      platform === "x" || platform === "twitter"
        ? `Your reply (max ${charLimit} chars)…`
        : "Your reply…  (Cmd/Ctrl+Enter to send)",
    oninput: (e) => {
      text = e.target.value;
      updateCounter();
    },
    onkeydown: (e) => {
      // Cmd+Enter / Ctrl+Enter to send — common shortcut across messaging apps
      if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
        e.preventDefault();
        e.stopPropagation();
        sendBtn.click();
      }
    },
  });

  // Auto-focus the textarea when the form mounts so the user can just type.
  setTimeout(() => textarea.focus(), 30);

  const form = el(
    "div",
    {
      class: "inbox-reply-area",
      style:
        "padding: 10px; background: var(--bg-1); border-radius: var(--radius-sm); border: 1px solid var(--border);",
      onclick: (e) => e.stopPropagation(),
    },
    [
      el(
        "div",
        {
          class: "wizard-label",
          style:
            "margin-bottom: 4px; display: flex; align-items: center; justify-content: space-between;",
        },
        [
          el(
            "span",
            {},
            `Replying to ${recipientHint} via ${platform === "twitter" ? "X" : platform}`,
          ),
          counter,
        ],
      ),
      textarea,
      errBox,
      el("div", { style: "display: flex; gap: 6px; margin-top: 8px; align-items: center;" }, [
        sendBtn,
        el(
          "button",
          {
            class: "btn btn-tiny btn-secondary",
            type: "button",
            onclick: (ev) => {
              ev.stopPropagation();
              replySlot.replaceChildren();
            },
          },
          "Cancel",
        ),
        el(
          "span",
          {
            class: "muted small",
            style: "margin-left: auto;",
          },
          "Cmd+Enter to send",
        ),
      ]),
    ],
  );
  return form;
}

// Build the platform-specific deep-link buttons for one inbox reply row.
function inboxRowLinks(r) {
  const links = [];

  // 1. The strongest signal: a URL embedded in the event detail string
  //    (e.g. "Commented on @x: '...' | https://x.com/i/status/12345 | ...")
  const embeddedUrl = extractFirstUrl(r.detail);
  if (embeddedUrl) {
    links.push({ label: "\u2197 Open original", href: embeddedUrl, title: embeddedUrl });
  }

  // 2. Platform-profile / DM deep link from the contact handles
  const platform = (r.platform || "").toLowerCase();
  if ((platform === "x" || platform === "twitter") && r.twitter_handle) {
    const h = String(r.twitter_handle).replace(/^@/, "");
    links.push({
      label: `@${h} on X \u2197`,
      href: `https://x.com/${h}`,
      title: `Open @${h} on x.com`,
    });
    links.push({
      label: "DM \u2197",
      href: `https://x.com/messages/compose?recipient_id=${encodeURIComponent(h)}`,
      title: "Compose DM (X may require numeric ID)",
    });
  } else if (platform === "linkedin" && r.linkedin_url) {
    links.push({ label: "LinkedIn profile \u2197", href: r.linkedin_url, title: r.linkedin_url });
    const slug = (r.linkedin_url.match(/\/in\/([^\/?#]+)/) || [])[1];
    if (slug) {
      links.push({
        label: "LinkedIn DM \u2197",
        href: `https://www.linkedin.com/messaging/compose/?recipient=${slug}`,
        title: "Compose LinkedIn message",
      });
    }
  } else if (platform === "telegram" && r.telegram_username) {
    const u = String(r.telegram_username).replace(/^@/, "");
    links.push({
      label: `@${u} on Telegram \u2197`,
      href: `https://t.me/${u}`,
      title: `Open @${u} on Telegram`,
    });
  } else if (platform === "email" && r.email) {
    links.push({
      label: `Reply to ${r.email} \u2197`,
      href: `mailto:${r.email}`,
      title: `Compose email to ${r.email}`,
    });
  }

  return links;
}

function extractFirstUrl(text) {
  if (!text) return null;
  const m = String(text).match(/https?:\/\/[^\s|<>"'\)]+/);
  return m ? m[0] : null;
}
