import { APP_ORIGIN } from "./config.js";

const status = document.querySelector("#status");
const account = document.querySelector("#account");
const authView = document.querySelector("#auth-view");
const authMessage = document.querySelector("#auth-message");
const signInButton = document.querySelector("#sign-in");
const checkSessionButton = document.querySelector("#check-session");
const switchAccountButton = document.querySelector("#switch-account");
const currentButton = document.querySelector("#open-current");
const homeView = document.querySelector("#home-view");
const signersView = document.querySelector("#signers-view");
const scanView = document.querySelector("#scan-view");
const scanHeading = document.querySelector("#scan-heading");
const candidateList = document.querySelector("#candidate-list");
const importSelected = document.querySelector("#import-selected");
const signerList = document.querySelector("#signer-list");
const pendingFile = document.querySelector("#pending-file");
const continueFields = document.querySelector("#continue-fields");
const addPdfButton = document.querySelector("#add-pdf");
const additionalPdfs = document.querySelector("#additional-pdfs");
const MAX_PDF_BYTES = 50 * 1024 * 1024;
const MAX_COMBINED_PAGES = 500;

const DASH_SIGN_PATHS = new Set(["/dashboard", "/documents", "/documents/new", "/templates", "/contacts", "/bulk-send", "/settings", "/workspace/pdf", "/extension/bridge"]);
let pendingPdf = null;
let sessionUser = null;
let signers = [{ full_name: "", email: "" }];
let discoveredCandidates = [];
let selectedCandidateIndexes = [];
const contactTimers = new Map();

function setStatus(message, error = false) {
  status.textContent = message;
  status.classList.toggle("error", error);
}

function isPdfUrl(url = "") {
  try {
    const parsed = new URL(url);
    return (parsed.protocol === "https:" || parsed.protocol === "file:") && parsed.pathname.toLowerCase().endsWith(".pdf");
  } catch {
    return false;
  }
}

function isGmailUrl(url = "") {
  try {
    const parsed = new URL(url);
    return parsed.protocol === "https:" && parsed.hostname === "mail.google.com";
  } catch {
    return false;
  }
}

function openDashSign(path) {
  const candidate = new URL(path, APP_ORIGIN);
  if (candidate.origin !== new URL(APP_ORIGIN).origin || (!DASH_SIGN_PATHS.has(candidate.pathname) && !/^\/documents\/[0-9a-f-]{36}\/fields$/i.test(candidate.pathname))) {
    setStatus("That Dash Sign destination is unavailable.", true);
    return;
  }
  candidate.searchParams.set("extension", "1");
  chrome.tabs.create({ url: candidate.href });
}

async function getActiveTab() {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  return tab;
}

function validatePdf(bytes) {
  if (!(bytes instanceof ArrayBuffer) && !(bytes instanceof Uint8Array)) {
    throw new Error("The selected PDF could not be read safely.");
  }
  if (bytes.byteLength > MAX_PDF_BYTES) {
    throw new Error("This PDF is larger than the 50 MB extension limit.");
  }
  const signature = new Uint8Array(bytes.slice(0, 4));
  if (String.fromCharCode(...signature) !== "%PDF") {
    throw new Error("The selected file is not available as a PDF yet. Wait for it to finish loading and try again.");
  }
}

function setAuthenticatedUser(user) {
  sessionUser = user;
  const label = user?.email ? `Signed in as ${user.email}` : "Signed in to Dash Sign";
  account.textContent = label;
  authView.classList.toggle("hidden", Boolean(user));
  homeView.classList.toggle("hidden", !user);
  switchAccountButton.classList.toggle("hidden", !user);
  if (user) {
    authMessage.textContent = `Signed in as ${user.email || "your Dash Sign account"}. Your credentials stay on Dash Sign.`;
    setStatus("");
  }
}

function openLogin() {
  const loginUrl = new URL("/login", APP_ORIGIN);
  loginUrl.searchParams.set("extension", "1");
  chrome.tabs.create({ url: loginUrl.href });
  authMessage.textContent = "Sign in in the Dash Sign tab, then return here and choose ‘check again’.";
  setStatus("Waiting for Dash Sign sign-in…");
}

async function checkPortalSession() {
  const tabs = await chrome.tabs.query({ url: `${APP_ORIGIN}/*` });
  const portalTab = tabs.find((tab) => typeof tab.id === "number" && tab.status === "complete");
  if (portalTab?.id === undefined) return null;
  const nonce = crypto.randomUUID();
  const [result] = await chrome.scripting.executeScript({
    target: { tabId: portalTab.id },
    args: [nonce],
    func: async (authorizationNonce) => {
      const response = await fetch(`${location.origin}/api/extension/authorize`, {
        method: "POST",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ nonce: authorizationNonce }),
      });
      return { status: response.status, data: await response.json().catch(() => null) };
    },
  });
  const payload = result?.result;
  if (payload?.status !== 200 || payload.data?.authorized !== true || payload.data?.nonce !== nonce) return null;
  return payload.data.user;
}

async function refreshSession() {
  checkSessionButton.disabled = true;
  authMessage.textContent = "Checking your Dash Sign session…";
  try {
    const user = await checkPortalSession();
    if (user) {
      setAuthenticatedUser(user);
      return true;
    }
    setAuthenticatedUser(null);
    authMessage.textContent = "Sign in to Dash Sign in a browser tab, then choose ‘check again’. The extension never stores your password or session token.";
    return false;
  } catch {
    setAuthenticatedUser(null);
    authMessage.textContent = "Dash Sign could not verify the session. Open Dash Sign, sign in, and try again.";
    return false;
  } finally {
    checkSessionButton.disabled = false;
  }
}

function requireAuthenticatedSession() {
  if (sessionUser) return true;
  setAuthenticatedUser(null);
  setStatus("Sign in to Dash Sign before using this action.", true);
  return false;
}

async function searchContacts(query) {
  const portalTab = await getAuthenticatedPortalTab();
  const [result] = await chrome.scripting.executeScript({
    target: { tabId: portalTab.id },
    args: [query],
    func: async (search) => {
      const response = await fetch(`${location.origin}/api/contacts?q=${encodeURIComponent(search)}&limit=5`, { credentials: "include" });
      return { status: response.status, data: await response.json().catch(() => null) };
    },
  });
  const payload = result?.result;
  if (payload?.status === 401) {
    setAuthenticatedUser(null);
    throw new Error("Your Dash Sign session expired. Sign in again to search contacts.");
  }
  if (payload?.status !== 200) throw new Error("Contacts could not be loaded right now.");
  return Array.isArray(payload.data?.contacts) ? payload.data.contacts.slice(0, 5) : [];
}

function hideContactSuggestions(suggestions) {
  suggestions.classList.add("hidden");
  suggestions.replaceChildren();
}

function showContactSuggestions(suggestions, contacts, onSelect) {
  suggestions.replaceChildren();
  if (!contacts.length) {
    hideContactSuggestions(suggestions);
    return;
  }
  contacts.forEach((contact) => {
    const option = document.createElement("button");
    option.type = "button";
    option.className = "contact-option";
    option.setAttribute("role", "option");
    const name = document.createElement("strong");
    name.textContent = contact.full_name || contact.email;
    const email = document.createElement("span");
    email.textContent = contact.email;
    option.append(name, email);
    option.addEventListener("click", () => onSelect(contact));
    suggestions.appendChild(option);
  });
  suggestions.classList.remove("hidden");
}

function renderSigners() {
  signerList.innerHTML = "";
  signers.forEach((signer, index) => {
    const card = document.createElement("div");
    card.className = "signer-card";
    card.innerHTML = `
      <div class="signer-heading"><span>Signer ${index + 1}</span>${signers.length > 1 ? '<button type="button" class="remove">Remove</button>' : ""}</div>
      <input type="text" aria-label="Signer ${index + 1} full name" placeholder="Full name" value="${escapeAttribute(signer.full_name)}" />
      <div class="contact-wrap"><input type="email" aria-label="Signer ${index + 1} email" placeholder="email@example.com" value="${escapeAttribute(signer.email)}" /><div class="contact-suggestions hidden" role="listbox"></div></div>
    `;
    const [nameInput, emailInput] = card.querySelectorAll("input");
    const suggestions = card.querySelector(".contact-suggestions");
    nameInput.addEventListener("input", () => { signers[index].full_name = nameInput.value; updateContinueState(); });
    emailInput.addEventListener("input", () => {
      signers[index].email = emailInput.value;
      updateContinueState();
      const query = emailInput.value.trim();
      clearTimeout(contactTimers.get(index));
      if (query.length < 2 || !sessionUser) {
        hideContactSuggestions(suggestions);
        return;
      }
      contactTimers.set(index, setTimeout(async () => {
        try {
          const contacts = await searchContacts(query);
          showContactSuggestions(suggestions, contacts, (contact) => {
            signers[index].full_name = contact.full_name || signers[index].full_name;
            signers[index].email = contact.email;
            nameInput.value = signers[index].full_name;
            emailInput.value = signers[index].email;
            hideContactSuggestions(suggestions);
            updateContinueState();
          });
        } catch (error) {
          hideContactSuggestions(suggestions);
          setStatus(error instanceof Error ? error.message : "Contacts could not be loaded.", true);
        }
      }, 250));
    });
    emailInput.addEventListener("blur", () => setTimeout(() => hideContactSuggestions(suggestions), 150));
    card.querySelector(".remove")?.addEventListener("click", () => {
      signers = signers.filter((_, itemIndex) => itemIndex !== index);
      renderSigners();
    });
    signerList.appendChild(card);
  });
  updateContinueState();
}

function escapeAttribute(value = "") {
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}

function updateContinueState() {
  const valid = Boolean(pendingPdf) && signers.length > 0 && signers.every((signer) => {
    return signer.full_name.trim().length > 0 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(signer.email.trim());
  });
  continueFields.disabled = !valid;
}

function showSignerStep(file) {
  pendingPdf = file;
  signers = [{ full_name: "", email: "" }];
  pendingFile.textContent = `PDF ready: ${file.fileName}`;
  homeView.classList.add("hidden");
  scanView.classList.add("hidden");
  signersView.classList.remove("hidden");
  setStatus("");
  renderSigners();
}

function showHome() {
  pendingPdf = null;
  if (!sessionUser) {
    authView.classList.remove("hidden");
    homeView.classList.add("hidden");
    signersView.classList.add("hidden");
    scanView.classList.add("hidden");
    return;
  }
  homeView.classList.remove("hidden");
  signersView.classList.add("hidden");
  scanView.classList.add("hidden");
  setStatus("");
}

async function createDocumentFromPendingPdf() {
  if (!pendingPdf) return;
  continueFields.disabled = true;
  setStatus("Creating agreement with the signer list…");
  try {
    const portalTab = await getAuthenticatedPortalTab();
    const { status: responseStatus, data } = await uploadDocumentThroughPortalTab(portalTab.id, {
      bytes: pendingPdf.bytes,
      fileName: pendingPdf.fileName,
      source: pendingPdf.source,
      signers: signers.map((signer) => ({ full_name: signer.full_name.trim(), email: signer.email.trim() })),
    });
    if (responseStatus < 200 || responseStatus >= 300 || typeof data?.id !== "string") {
      throw new Error(typeof data?.error === "string" ? data.error : "Dash Sign could not create this agreement.");
    }
    setStatus("Agreement created. Opening field preparation…");
    openDashSign(`/documents/${data.id}/fields`);
  } catch (error) {
    setStatus(error instanceof Error ? error.message : "Could not create the agreement.", true);
    continueFields.disabled = false;
  }
}

async function getAuthenticatedPortalTab() {
  const tabs = await chrome.tabs.query({ url: `${APP_ORIGIN}/*` });
  const existing = tabs.find((tab) => typeof tab.id === "number" && tab.status === "complete");
  if (existing?.id !== undefined) return existing;
  const tab = await chrome.tabs.create({ url: `${APP_ORIGIN}/dashboard?extension=1`, active: false });
  if (tab.id === undefined) throw new Error("Dash Sign could not open an authenticated workspace tab.");
  await new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      chrome.tabs.onUpdated.removeListener(listener);
      reject(new Error("Dash Sign took too long to open the authenticated workspace."));
    }, 15000);
    const listener = (updatedTabId, changeInfo) => {
      if (updatedTabId !== tab.id || changeInfo.status !== "complete") return;
      clearTimeout(timeout);
      chrome.tabs.onUpdated.removeListener(listener);
      resolve();
    };
    chrome.tabs.onUpdated.addListener(listener);
  });
  return tab;
}

function arrayBufferToBase64(buffer) {
  const bytes = new Uint8Array(buffer);
  let binary = "";
  for (let index = 0; index < bytes.length; index += 0x8000) {
    binary += String.fromCharCode(...bytes.subarray(index, index + 0x8000));
  }
  return btoa(binary);
}

async function uploadDocumentThroughPortalTab(tabId, documentInput) {
  const bytesBase64 = arrayBufferToBase64(documentInput.bytes);
  const [result] = await chrome.scripting.executeScript({
    target: { tabId },
    args: [bytesBase64, documentInput.fileName, documentInput.source || "Extension import", documentInput.signers.map((signer) => ({
      full_name: String(signer.full_name || ""),
      email: String(signer.email || ""),
    }))],
    func: async (encodedBytes, fileName, source, signerList) => {
      const binary = atob(encodedBytes);
      const bytes = new Uint8Array(binary.length);
      for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
      const formData = new FormData();
      formData.append("file", new File([bytes], fileName, { type: "application/pdf" }));
      formData.append("metadata", JSON.stringify({ source, extension_flow: "import-then-add-signers" }));
      formData.append("signers", JSON.stringify(signerList));
      const response = await fetch(`${location.origin}/api/documents`, {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: { "X-Dash-Sign-Extension": "1" },
      });
      return { status: response.status, data: await response.json().catch(() => null) };
    },
  });
  if (!result?.result) throw new Error("Dash Sign did not return a document response.");
  return result.result;
}

async function findGmailPdf(tabId) {
  const [result] = await chrome.scripting.executeScript({
    target: { tabId },
    func: () => {
      const nodes = Array.from(document.querySelectorAll("a[href], iframe[src], embed[src], object[data], [data-tooltip], [aria-label]"));
      const candidates = nodes.flatMap((node) => {
        const rawUrl = node.getAttribute("href") || node.getAttribute("src") || node.getAttribute("data");
        if (!rawUrl) return [];
        const label = [node.textContent, node.getAttribute("aria-label"), node.getAttribute("data-tooltip"), node.getAttribute("title")].filter(Boolean).join(" ");
        let url;
        try { url = new URL(rawUrl, location.href); } catch { return []; }
        if (url.origin !== location.origin) return [];
        const hasAttachmentQuery = url.searchParams.has("attid") && url.searchParams.get("view") === "att";
        const looksLikePdf = /\.pdf(?:$|[?#])/i.test(url.pathname + url.search) || /\bpdf\b/i.test(label);
        if (!hasAttachmentQuery && !looksLikePdf) return [];
        return [{ url: url.href, label: label.trim() }];
      });
      const unique = [];
      for (const candidate of candidates) if (!unique.some((item) => item.url === candidate.url)) unique.push(candidate);
      const preferred = unique.find((item) => /\.pdf\b/i.test(item.label)) || unique.find((item) => item.url.includes("attid=")) || unique[0];
      if (!preferred) return null;
      const nameMatch = preferred.label.match(/[\w .()\-]+\.pdf\b/i);
      return { url: preferred.url, fileName: nameMatch?.[0]?.trim() || "Gmail attachment.pdf" };
    },
  });
  return result?.result || null;
}

async function discoverPageCandidates(tabId) {
  const [result] = await chrome.scripting.executeScript({
    target: { tabId },
    func: () => {
      const candidates = [];
      const add = (rawUrl, label, kind) => {
        if (!rawUrl) return;
        let url;
        try { url = new URL(rawUrl, location.href); } catch { return; }
        if (!["https:", "blob:", "file:"].includes(url.protocol)) return;
        const text = [label, url.pathname, url.search].filter(Boolean).join(" ");
        const looksLikePdf = /\.pdf(?:$|[?#])/i.test(text) || /\bpdf\b/i.test(text) || url.protocol === "blob:";
        if (!looksLikePdf) return;
        if (!candidates.some((candidate) => candidate.url === url.href)) {
          candidates.push({ url: url.href, label: label?.trim() || "PDF document", kind });
        }
      };
      const nodes = Array.from(document.querySelectorAll("a[href], iframe[src], embed[src], object[data], source[src], [data-url], [data-src], [data-pdf-url], [aria-label], [data-tooltip]"));
      for (const node of nodes) {
        const rawUrl = node.getAttribute("href") || node.getAttribute("src") || node.getAttribute("data") || node.getAttribute("data-url") || node.getAttribute("data-src") || node.getAttribute("data-pdf-url");
        const label = [node.textContent, node.getAttribute("download"), node.getAttribute("aria-label"), node.getAttribute("data-tooltip"), node.getAttribute("title")].filter(Boolean).join(" ");
        add(rawUrl, label, node.tagName.toLowerCase());
      }
      for (const entry of performance.getEntriesByType("resource")) add(entry.name, "Loaded PDF resource", "resource");
      add(location.href, document.title, "page");
      return candidates.slice(0, 12);
    },
  });
  return result?.result || [];
}

function viewerSourceUrl(url = "") {
  try {
    const parsed = new URL(url);
    const source = parsed.searchParams.get("file");
    return source && /^(https:|file:|blob:)/i.test(source) ? source : null;
  } catch {
    return null;
  }
}

function candidateFileName(candidate) {
  if (candidate.fileName) return candidate.fileName;
  try {
    const path = decodeURIComponent(new URL(candidate.url).pathname.split("/").pop() || "document");
    return /\.pdf$/i.test(path) ? path : `${path}.pdf`;
  } catch {
    return "document.pdf";
  }
}

function candidateSourceLabel(candidate, activeTabUrl) {
  try {
    const source = new URL(candidate.url);
    if (source.protocol === "blob:") return `Blob on ${new URL(activeTabUrl).hostname}`;
    if (source.protocol === "file:") return "Local file";
    return source.hostname;
  } catch {
    return "Current page";
  }
}

async function readPdfCandidate(tabId, candidate, activeTabUrl) {
  let sameOrigin = false;
  try {
    sameOrigin = new URL(candidate.url).origin === new URL(activeTabUrl).origin;
  } catch {
    sameOrigin = false;
  }
  const readResponse = async (response) => {
    const declaredLength = Number(response.headers.get("content-length"));
    if (Number.isFinite(declaredLength) && declaredLength > MAX_PDF_BYTES) {
      throw new Error("This PDF is larger than the 50 MB extension limit.");
    }
    if (!response.body) {
      const bytes = await response.arrayBuffer();
      validatePdf(bytes);
      return bytes;
    }
    const reader = response.body.getReader();
    const chunks = [];
    let total = 0;
    try {
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        total += value.byteLength;
        if (total > MAX_PDF_BYTES) {
          await reader.cancel();
          throw new Error("This PDF is larger than the 50 MB extension limit.");
        }
        chunks.push(value);
      }
    } finally {
      reader.releaseLock();
    }
    const bytes = new Uint8Array(total);
    let offset = 0;
    for (const chunk of chunks) {
      bytes.set(chunk, offset);
      offset += chunk.byteLength;
    }
    validatePdf(bytes);
    return bytes.buffer;
  };
  if (candidate.url.startsWith("file:")) {
    const response = await fetch(candidate.url);
    if (!response.ok) throw new Error("The local PDF could not be read.");
    return readResponse(response);
  }
  try {
    const [result] = await chrome.scripting.executeScript({
      target: { tabId },
      args: [candidate.url, MAX_PDF_BYTES, sameOrigin],
      func: async (sourceUrl, maxBytes, includeCredentials) => {
        try {
          const response = await fetch(sourceUrl, { credentials: includeCredentials ? "include" : "omit" });
          if (!response.ok) return { error: `PDF source returned ${response.status}.` };
          const declaredLength = Number(response.headers.get("content-length"));
          if (Number.isFinite(declaredLength) && declaredLength > maxBytes) return { error: "This PDF is larger than the 50 MB extension limit." };
          const reader = response.body?.getReader();
          if (!reader) return { error: "The PDF source could not be read safely." };
          const byteChunks = [];
          let total = 0;
          while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            total += value.byteLength;
            if (total > maxBytes) {
              await reader.cancel();
              return { error: "This PDF is larger than the 50 MB extension limit." };
            }
            byteChunks.push(value);
          }
          const bytes = new Uint8Array(total);
          let offset = 0;
          for (const chunk of byteChunks) { bytes.set(chunk, offset); offset += chunk.byteLength; }
          const base64Chunks = [];
          for (let index = 0; index < bytes.length; index += 0x8000) {
            base64Chunks.push(String.fromCharCode(...bytes.subarray(index, index + 0x8000)));
          }
          return { base64: btoa(base64Chunks.join("")) };
        } catch {
          return { error: "The page did not allow Dash Sign to read this PDF source." };
        }
      },
    });
    const data = result?.result;
    if (!data?.base64) throw new Error(data?.error || "The page did not allow Dash Sign to read this PDF source.");
    const binary = atob(data.base64);
    const bytes = new Uint8Array(binary.length);
    for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
    return bytes.buffer;
  } catch (pageError) {
    if (candidate.url.startsWith("blob:")) throw pageError;
    const response = await fetch(candidate.url, { credentials: sameOrigin ? "include" : "omit" });
    if (!response.ok) throw new Error(`PDF source returned ${response.status}.`);
    return readResponse(response);
  }
}

function renderCandidates() {
  candidateList.innerHTML = "";
  if (discoveredCandidates.length === 0) {
    candidateList.innerHTML = '<div class="file-card">No accessible PDF was found on this page. Open the document preview or use Upload PDF.</div>';
    importSelected.disabled = true;
    return;
  }
  discoveredCandidates.forEach((candidate, index) => {
    const card = document.createElement("label");
    card.className = "signer-card candidate-card";
    card.innerHTML = `<div class="candidate-main"><input type="checkbox" name="pdf-candidate" value="${index}" ${selectedCandidateIndexes.includes(index) ? "checked" : ""}><div class="candidate-copy"><strong>${escapeAttribute(candidate.fileName)}</strong><span class="detail">${escapeAttribute(candidate.kind || "PDF source")} · ${escapeAttribute(candidate.source || "Current page")}</span></div></div><span class="candidate-index">PDF ${index + 1}</span>`;
    card.querySelector("input").addEventListener("change", () => {
      if (card.querySelector("input").checked) selectedCandidateIndexes.push(index);
      else selectedCandidateIndexes = selectedCandidateIndexes.filter((item) => item !== index);
      updateCombineButton();
      account.textContent = selectedCandidateIndexes.length === 1 ? `Ready: ${candidate.fileName}` : `${selectedCandidateIndexes.length} PDFs selected`;
    });
    candidateList.appendChild(card);
  });
  updateCombineButton();
}

function updateCombineButton() {
  importSelected.disabled = selectedCandidateIndexes.length === 0;
  importSelected.textContent = selectedCandidateIndexes.length > 1 ? `Combine ${selectedCandidateIndexes.length} PDFs and prepare` : "Prepare selected PDF";
}

async function addLocalPdfs(files) {
  const pdfFiles = Array.from(files || []);
  if (!pdfFiles.length) return;
  addPdfButton.disabled = true;
  setStatus(`Adding ${pdfFiles.length} PDF${pdfFiles.length === 1 ? "" : "s"}…`);
  try {
    let added = 0;
    for (const file of pdfFiles) {
      if (file.type && file.type !== "application/pdf" && !/\.pdf$/i.test(file.name)) continue;
      const bytes = await file.arrayBuffer();
      validatePdf(bytes);
      const duplicate = discoveredCandidates.some((candidate) => candidate.fileName === file.name && candidate.source === "Local file");
      if (duplicate) continue;
      discoveredCandidates.push({
        bytes,
        fileName: file.name || "Local document.pdf",
        source: "Local file",
        kind: "Added PDF",
        url: `file://${encodeURIComponent(file.name || "document.pdf")}`,
      });
      added += 1;
    }
    renderCandidates();
    setStatus(added ? `${added} PDF${added === 1 ? "" : "s"} added. Select the files in signing order.` : "No new PDF files were added.", !added);
  } catch (error) {
    setStatus(error instanceof Error ? error.message : "Could not add the PDF files.", true);
  } finally {
    addPdfButton.disabled = false;
    additionalPdfs.value = "";
  }
}

async function combineSelectedCandidates() {
  const selected = selectedCandidateIndexes.map((index) => discoveredCandidates[index]).filter(Boolean);
  if (!selected.length) return;
  importSelected.disabled = true;
  setStatus(selected.length > 1 ? `Combining ${selected.length} PDFs…` : "Preparing selected PDF…");
  try {
    if (selected.length === 1) {
      showSignerStep(selected[0]);
      return;
    }
    if (!window.PDFLib?.PDFDocument) throw new Error("PDF combining is unavailable. Use Upload PDF instead.");
    const merged = await window.PDFLib.PDFDocument.create();
    let totalPages = 0;
    for (const candidate of selected) {
      const source = await window.PDFLib.PDFDocument.load(candidate.bytes);
      totalPages += source.getPageCount();
      if (totalPages > MAX_COMBINED_PAGES) throw new Error("The combined agreement cannot exceed 500 pages.");
      const pages = await merged.copyPages(source, source.getPageIndices());
      pages.forEach((page) => merged.addPage(page));
    }
    const bytes = await merged.save();
    showSignerStep({
      bytes,
      fileName: `Combined agreement (${selected.length} PDFs).pdf`,
      source: selected.map((candidate) => candidate.source).filter(Boolean).join(", "),
    });
  } catch (error) {
    setStatus(error instanceof Error ? error.message : "Could not combine the selected PDFs.", true);
    importSelected.disabled = false;
  }
}

async function scanCurrentTab() {
  currentButton.disabled = true;
  discoveredCandidates = [];
  selectedCandidateIndexes = [];
  try {
    const tab = await getActiveTab();
    if (!tab?.id || !tab.url) throw new Error("Dash Sign could not inspect this tab.");
    setStatus("Scanning this tab for PDFs…");
    const candidates = [];
    if (isPdfUrl(tab.url)) candidates.push({ url: tab.url, label: tab.title || "PDF document", kind: "current tab" });
    const viewerSource = viewerSourceUrl(tab.url);
    if (viewerSource) candidates.push({ url: viewerSource, label: tab.title || "PDF viewer source", kind: "viewer source" });
    if (isGmailUrl(tab.url)) {
      const gmail = await findGmailPdf(tab.id).catch(() => null);
      if (gmail) candidates.push({ ...gmail, label: gmail.fileName, kind: "Gmail attachment" });
    }
    const pageCandidates = await discoverPageCandidates(tab.id).catch(() => []);
    for (const candidate of [...candidates, ...pageCandidates]) {
      if (!candidates.some((item) => item.url === candidate.url)) candidates.push(candidate);
    }
    for (const candidate of candidates.slice(0, 12)) {
      setStatus(`Checking ${candidateFileName(candidate)}…`);
      try {
        const bytes = await readPdfCandidate(tab.id, candidate, tab.url);
        validatePdf(bytes);
        discoveredCandidates.push({ ...candidate, bytes, fileName: candidateFileName(candidate), source: candidateSourceLabel(candidate, tab.url) });
      } catch {
        // Candidate URLs are only hints; keep scanning until a real PDF is verified.
      }
    }
    homeView.classList.add("hidden");
    signersView.classList.add("hidden");
    scanView.classList.remove("hidden");
    scanHeading.textContent = discoveredCandidates.length ? `PDFs found on this page · ${discoveredCandidates.length}` : "PDFs found on this page";
    renderCandidates();
    setStatus(discoveredCandidates.length ? "" : "No accessible PDF found.", !discoveredCandidates.length);
  } catch (error) {
    setStatus(error instanceof Error ? error.message : "Unable to scan this tab.", true);
  } finally {
    currentButton.disabled = false;
  }
}

async function openCurrentPdf() {
  await scanCurrentTab();
}

async function initialize() {
  const tab = await getActiveTab().catch(() => undefined);
  if (tab?.url && isPdfUrl(tab.url)) {
    account.textContent = `Ready: ${candidateFileName({ url: tab.url })}`;
    return;
  }
  if (tab?.id && tab.url && isGmailUrl(tab.url)) {
    const gmail = await findGmailPdf(tab.id).catch(() => null);
    account.textContent = gmail?.fileName ? `Ready: ${gmail.fileName}` : "Open a PDF to prepare it from here";
    return;
  }
  account.textContent = "Open a PDF to prepare it from here";
}

currentButton.addEventListener("click", () => { if (requireAuthenticatedSession()) void openCurrentPdf(); });
signInButton.addEventListener("click", openLogin);
checkSessionButton.addEventListener("click", () => void refreshSession());
switchAccountButton.addEventListener("click", () => {
  setAuthenticatedUser(null);
  const loginUrl = new URL("/login", APP_ORIGIN);
  loginUrl.searchParams.set("extension", "1");
  loginUrl.searchParams.set("switch", "1");
  chrome.tabs.create({ url: loginUrl.href });
});
document.querySelector("#back-from-scan").addEventListener("click", showHome);
document.querySelector("#scan-again").addEventListener("click", () => { if (requireAuthenticatedSession()) void scanCurrentTab(); });
addPdfButton.addEventListener("click", () => { if (requireAuthenticatedSession()) additionalPdfs.click(); });
additionalPdfs.addEventListener("change", () => { if (requireAuthenticatedSession()) void addLocalPdfs(additionalPdfs.files); });
importSelected.addEventListener("click", () => { if (requireAuthenticatedSession()) void combineSelectedCandidates(); });
document.querySelector("#back-home").addEventListener("click", showHome);
document.querySelector("#add-signer").addEventListener("click", () => {
  if (!requireAuthenticatedSession()) return;
  signers.push({ full_name: "", email: "" });
  renderSigners();
});
continueFields.addEventListener("click", () => { if (requireAuthenticatedSession()) void createDocumentFromPendingPdf(); });
document.querySelector("#open-workspace").addEventListener("click", () => { if (requireAuthenticatedSession()) openDashSign("/workspace/pdf"); });
document.querySelector("#upload").addEventListener("click", () => { if (requireAuthenticatedSession()) openDashSign("/documents/new?source=extension"); });
document.querySelectorAll("[data-path]").forEach((button) => button.addEventListener("click", () => { if (requireAuthenticatedSession()) openDashSign(button.getAttribute("data-path")); }));
void refreshSession().then((authenticated) => { if (authenticated) void initialize(); });