// Главный скрипт просмотрщика: загрузка PDF, UI, AI-панель, закладки, поиск.

import { PdfController } from "./pdf-controller.js";
import { DocumentContext, ask } from "../ai/assistant.js";
import { QUICK_ACTIONS, SELECTION_PROMPTS, profileList, quickActionLabel } from "../ai/profiles.js";
import { suggestBookmarks, compareDocs } from "../ai/offline.js";
import { ensureText, pageLooksScanned } from "../ocr/ocr.js";
import { getSettings, setSettings, pushHistory, getHistory } from "../common/storage.js";
import { setLang, resolveLang, getLang, t, applyI18n } from "../common/i18n.js";
import { syncKeys, pushKey } from "../cloud/sync.js";
import * as collab from "../cloud/collab.js";

const $ = (sel) => document.querySelector(sel);

// --- Разбор ?file= (DNR подставляет сырой URL без кодирования) --------------
function getFileUrl() {
  const href = location.href;
  const idx = href.indexOf("?file=");
  if (idx === -1) return null;
  let raw = href.slice(idx + 6);
  try {
    raw = decodeURIComponent(raw);
  } catch {
    /* уже декодирован */
  }
  return raw;
}

const state = {
  pdf: null,
  doc: new DocumentContext(),
  fileUrl: null,
  pdfBlob: null,
  scale: 1,
  searchHits: [],
  searchIdx: -1,
  searchTotal: 0,
  searchOpts: { caseSensitive: false, wholeWord: false, regex: false },
  fitMode: null,
  drawing: false,
  drawColor: "#ef4444",
  drawShape: "pencil",
  drawWidth: 2,
  redoStack: [],
  annotations: [],
  resumeReady: false, // чтобы стартовый onPageChange(1) не перезаписал сохранённую страницу
  abort: null,
};

// ---------------------------------------------------------------------------
// Загрузка документа
// ---------------------------------------------------------------------------

async function boot() {
  const s0 = await getSettings();
  setLang(resolveLang(s0.language));
  setupUI();
  setupDropAndOpen();
  state.fileUrl = getFileUrl();
  if (!state.fileUrl) {
    showOpenPrompt();
    return;
  }
  const name = decodeURIComponent(state.fileUrl.split("/").pop()?.split("?")[0] || "document.pdf");
  try {
    setStatus(t("st.loading"));
    const res = await fetch(state.fileUrl);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const blob = await res.blob();
    await loadDocument(await blob.arrayBuffer(), name, state.fileUrl, blob);
  } catch (e) {
    showError(e);
  }
}

/** Запрос пароля у пользователя (pdf.js onPassword). */
function promptPassword(reason) {
  return window.prompt(reason === 2 ? t("st.password.wrong") : t("st.password"));
}

/** Полный конвейер загрузки документа из буфера. */
async function loadDocument(buf, name, url, blob) {
  state.fileUrl = url || null;
  state.pdfBlob = blob || new Blob([buf], { type: "application/pdf" });
  $("#doc-title").textContent = name;
  document.title = `${name} — Aris PDF AI`;

  state.pdf = new PdfController($("#pages"), $("#viewer-container"));
  state.pdf.onPageChange = onPageChange;
  state.pdf.onPageRendered = renderAnnotationsForPage;

  setStatus(t("st.loading"));
  const pages = await state.pdf.load(buf.slice(0), promptPassword);
  if (!pages) throw new Error(t("st.empty"));
  $("#page-total").textContent = pages;

  setStatus(t("st.extract"));
  let pageText = await state.pdf.extractAllText();

  setStatus(t("st.render"));
  state.pdf.buildPages();

  setStatus(t("st.ocrcheck"));
  pageText = await ensureText({
    pages: pageText,
    renderPage: (i) => state.pdf.pageToCanvas(i, 2),
    onProgress: (done, total, page) =>
      setStatus(page ? `OCR ${page} (${done}/${total})…` : "OCR"),
  });

  state.doc.setPages(pageText);
  state.pdf.pageText = pageText; // OCR-текст идёт и в поиск/подсветку, не только в AI
  state.doc.title = name;
  state.doc.hash = await sha256(buf);

  await buildOutline();
  await buildThumbnails();
  loadBookmarks();
  await loadAnnotations();
  await pushHistory("documents", { hash: state.doc.hash, title: name, url: state.fileUrl, openedAt: Date.now() });
  await restoreRotation();
  await applyInvert();
  await restoreLastPage();
  if (state.viewMode === "single") showSinglePage(+$("#page-input").value || 1);

  hideStatus();
  maybeShowOcrBanner();
  syncOnOpen();
}

/** Облачная синхронизация при открытии документа (аннотации + закладки). */
async function syncOnOpen() {
  if (!state.doc.hash) return;
  try {
    const { changed } = await syncKeys([annKey(), bookmarkKey()]);
    if (changed.includes(annKey())) {
      await loadAnnotations();
      for (const n of state.pdf.rendered) renderAnnotationsForPage(n, state.pdf.wraps.get(n));
    }
    if (changed.includes(bookmarkKey())) await loadBookmarks();
  } catch (e) {
    console.warn("[Aris sync]", e.message);
  }
  startCollab();
}

// --- Совместная работа в реальном времени (М11) ----------------------------

/** Подключиться к комнате документа: живой обмен аннотациями/закладками. */
async function startCollab() {
  if (!state.doc.hash) return;
  collab.disconnect();
  try {
    await collab.connect(state.doc.hash, {
      onAnnotations: applyRemoteAnnotations,
      onBookmarks: applyRemoteBookmarks,
      onPeers: updateCollabPeers,
    });
  } catch (e) {
    console.warn("[Aris collab]", e.message);
  }
}

/** Объединение массивов без потерь (union по ключу элемента). */
function unionBy(arr, remote, keyOf) {
  const map = new Map();
  for (const x of arr || []) map.set(keyOf(x), x);
  for (const x of remote || []) if (!map.has(keyOf(x))) map.set(keyOf(x), x);
  return [...map.values()];
}

/** Применить аннотации, пришедшие от другого участника (без повторной рассылки). */
async function applyRemoteAnnotations(key, remote) {
  if (key !== annKey()) return;
  const merged = unionBy(state.annotations, remote, (a) => a.id);
  if (merged.length === state.annotations.length) return; // ничего нового
  state.annotations = merged;
  await chrome.storage.local.set({ [annKey()]: merged });
  for (const n of state.pdf.rendered) renderAnnotationsForPage(n, state.pdf.wraps.get(n));
  renderCommentsList();
}

/** Применить закладки от другого участника. */
async function applyRemoteBookmarks(key, remote) {
  if (key !== bookmarkKey()) return;
  const { [bookmarkKey()]: local = [] } = await chrome.storage.local.get(bookmarkKey());
  const merged = unionBy(local, remote, (b) => `${b.page}|${b.title}|${b.ai ? 1 : 0}`);
  if (merged.length === local.length) return;
  await chrome.storage.local.set({ [bookmarkKey()]: merged });
  renderBookmarks(merged);
}

/** Индикатор присутствия участников в правом верхнем углу. */
function updateCollabPeers(participants, type) {
  if (Array.isArray(participants)) state.collabPeers = participants.length;
  else if (type === "join") state.collabPeers = (state.collabPeers || 1) + 1;
  else if (type === "leave") state.collabPeers = Math.max(1, (state.collabPeers || 1) - 1);
  let badge = $("#collab-badge");
  if (!badge) {
    badge = document.createElement("div");
    badge.id = "collab-badge";
    badge.style.cssText =
      "position:fixed;top:8px;right:12px;z-index:60;background:#10b981;color:#fff;" +
      "font:12px/1.6 system-ui,sans-serif;padding:2px 9px;border-radius:11px;" +
      "box-shadow:0 1px 4px rgba(0,0,0,.25);opacity:.92;pointer-events:none";
    document.body.appendChild(badge);
  }
  const n = state.collabPeers || 0;
  badge.textContent = `👥 ${n}`;
  badge.title = t("collab.peers") || "Совместный просмотр: участников онлайн";
  badge.style.display = n > 1 ? "block" : "none";
}

// --- OCR-баннер (скан) -----------------------------------------------------

function maybeShowOcrBanner() {
  const pages = state.doc.pages;
  if (!pages.length) return;
  const scanned = pages.filter(pageLooksScanned).length;
  $("#ocr-banner").classList.toggle("hidden", scanned / pages.length < 0.5);
}

async function runOcrNow() {
  $("#ocr-banner").classList.add("hidden");
  setStatus(t("ocr.running"));
  try {
    const pageText = await ensureText({
      pages: state.doc.pages,
      renderPage: (i) => state.pdf.pageToCanvas(i, 2),
      onProgress: (done, total, page) =>
        setStatus(page ? `OCR ${page} (${done}/${total})…` : t("ocr.running")),
    });
    state.doc.setPages(pageText);
  } catch (e) {
    console.warn("[Aris OCR]", e.message);
  }
  hideStatus();
  maybeShowOcrBanner();
}

// --- Открытие файла / drag&drop / ошибки ----------------------------------

function setupDropAndOpen() {
  const c = $("#viewer-container");
  ["dragover", "dragenter"].forEach((ev) =>
    c.addEventListener(ev, (e) => { e.preventDefault(); c.classList.add("dragover"); }));
  ["dragleave", "drop"].forEach((ev) =>
    c.addEventListener(ev, (e) => { e.preventDefault(); if (ev === "dragleave" && c.contains(e.relatedTarget)) return; c.classList.remove("dragover"); }));
  c.addEventListener("drop", async (e) => {
    const file = [...(e.dataTransfer?.files || [])].find((f) => /\.pdf$/i.test(f.name) || f.type === "application/pdf");
    if (file) {
      try { setStatus(t("st.loading")); await loadDocument(await file.arrayBuffer(), file.name, null, file); }
      catch (err) { showError(err); }
    }
  });

  const input = $("#open-file");
  input.onchange = async (e) => {
    const file = e.target.files?.[0];
    e.target.value = "";
    if (file) { try { setStatus(t("st.loading")); await loadDocument(await file.arrayBuffer(), file.name, null, file); } catch (err) { showError(err); } }
  };
}

async function showOpenPrompt() {
  const ov = $("#status-overlay");
  ov.classList.remove("hidden");
  // Недавние документы с URL (открытые по ссылке можно переоткрыть).
  let recent = [];
  try {
    const seen = new Set();
    recent = (await getHistory("documents"))
      .filter((d) => d.url && /^https?:/.test(d.url) && !seen.has(d.url) && seen.add(d.url))
      .slice(0, 8);
  } catch { /* нет истории */ }

  const recentHtml = recent.length
    ? `<div class="recent"><div class="muted">${t("st.recent")}</div><ul>` +
      recent.map((d, i) =>
        `<li data-i="${i}" title="${(d.url || "").replace(/"/g, "&quot;")}">${(d.title || d.url).slice(0, 60)}</li>`).join("") +
      `</ul></div>`
    : "";

  ov.innerHTML =
    `<div class="open-prompt"><button id="open-btn" class="primary-btn">${t("st.open")}</button>` +
    `<div class="muted">${t("st.drophint")}</div>${recentHtml}</div>`;
  $("#open-btn").onclick = () => $("#open-file").click();
  ov.querySelectorAll(".recent li").forEach((li) => {
    li.onclick = () => { location.href = recent[+li.dataset.i].url; }; // DNR редиректнёт на просмотрщик
  });
}

function showError(e) {
  console.error(e);
  const ov = $("#status-overlay");
  ov.classList.remove("hidden");
  const msg = e?.name === "PasswordException" ? t("st.empty") : `${t("st.loaderr")}: ${e?.message || e}`;
  ov.innerHTML =
    `<div class="open-prompt"><span id="status-text">${msg}</span>` +
    `<div style="display:flex;gap:8px;margin-top:10px;">` +
    `<button id="retry-btn" class="primary-btn">${t("st.retry")}</button>` +
    `<button id="open-btn2" class="ghost-btn" style="width:auto;">${t("st.open")}</button></div></div>`;
  $("#retry-btn").onclick = () => location.reload();
  $("#open-btn2").onclick = () => $("#open-file").click();
}

// --- Тема ------------------------------------------------------------------

function resolveTheme(theme) {
  if (theme === "light" || theme === "dark") return theme;
  return window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
}
async function applyTheme() {
  const { theme } = await getSettings();
  const resolved = resolveTheme(theme);
  document.documentElement.dataset.theme = resolved;
  $("#btn-theme").textContent = resolved === "light" ? "☀️" : "🌙";
}
async function applyViewMode() {
  const { viewMode } = await getSettings();
  setViewMode(viewMode || "continuous");
}

function setViewMode(mode) {
  state.viewMode = mode;
  $("#pages").classList.toggle("mode-two", mode === "two");
  $("#pages").classList.toggle("mode-single", mode === "single");
  $("#view-mode").value = mode;
  if (mode === "single") showSinglePage(+$("#page-input").value || 1);
}

/** Показ одной страницы (режим single): прячем остальные, рендерим текущую. */
async function showSinglePage(n) {
  if (!state.pdf) return;
  for (const [num, wrap] of state.pdf.wraps) wrap.classList.toggle("single-current", num === n);
  await state.pdf.ensureRendered(n);
  $("#viewer-container").scrollTop = 0;
}

async function applyInvert() {
  const s = await getSettings();
  let on = !!s.invertPdf; // глобальный дефолт
  if (state.doc.hash) {
    const key = `invert_${state.doc.hash}`;
    const { [key]: perDoc } = await chrome.storage.local.get(key);
    if (typeof perDoc === "boolean") on = perDoc; // приоритет — настройка документа
  }
  $("#pages").classList.toggle("invert", on);
  $("#btn-invert").classList.toggle("active", on);
}
async function toggleInvert() {
  const on = !$("#pages").classList.contains("invert");
  $("#pages").classList.toggle("invert", on);
  $("#btn-invert").classList.toggle("active", on);
  if (state.doc.hash) await chrome.storage.local.set({ [`invert_${state.doc.hash}`]: on });
  else await setSettings({ invertPdf: on });
}

async function cycleTheme() {
  const { theme } = await getSettings();
  const next = { auto: "light", light: "dark", dark: "auto" }[theme] || "light";
  await setSettings({ theme: next });
  await applyTheme();
}

let _savePageTimer = null;
function onPageChange(n) {
  $("#page-input").value = n;
  document.querySelectorAll(".thumb").forEach((t) => t.classList.toggle("active", +t.dataset.page === n));
  // Запоминаем последнюю страницу документа (после восстановления, с задержкой).
  if (state.doc.hash && state.resumeReady) {
    clearTimeout(_savePageTimer);
    _savePageTimer = setTimeout(() => chrome.storage.local.set({ [`lastpage_${state.doc.hash}`]: n }), 600);
  }
}

async function restoreRotation() {
  if (!state.doc.hash) return;
  const key = `rotation_${state.doc.hash}`;
  const { [key]: rot } = await chrome.storage.local.get(key);
  if (rot) await state.pdf.setRotation(rot); // controller стартует с rotation 0
}

async function restoreLastPage() {
  if (!state.doc.hash) { state.resumeReady = true; return; }
  const key = `lastpage_${state.doc.hash}`;
  const { [key]: page } = await chrome.storage.local.get(key);
  if (page && page > 1 && page <= state.pdf.numPages) {
    setTimeout(() => { goToPage(page); state.resumeReady = true; }, 400);
  } else {
    state.resumeReady = true;
  }
}

// --- Доступность (a11y) ----------------------------------------------------

function setupA11y() {
  // aria-label из локализованного title для иконок/селектов
  document.querySelectorAll("[title]").forEach((el) => {
    if (!el.getAttribute("aria-label")) el.setAttribute("aria-label", el.getAttribute("title"));
  });
  const tabs = document.querySelector(".tabs");
  if (tabs) {
    tabs.setAttribute("role", "tablist");
    document.querySelectorAll(".tab").forEach((tb) => {
      tb.setAttribute("role", "tab");
      tb.setAttribute("aria-selected", tb.classList.contains("active") ? "true" : "false");
    });
  }
  $("#chat-messages")?.setAttribute("aria-live", "polite");
  $("#status-overlay")?.setAttribute("aria-live", "polite");
  $("#search-count")?.setAttribute("aria-live", "polite");
  $("#left-panel")?.setAttribute("role", "navigation");
  $("#right-panel")?.setAttribute("aria-label", t("ai.title"));
  $("#viewer-container")?.setAttribute("role", "document");
}

// --- Горячие клавиши -------------------------------------------------------

function setupKeyboard() {
  document.addEventListener("keydown", (e) => {
    const tag = (e.target.tagName || "").toLowerCase();
    const typing = tag === "input" || tag === "textarea";

    if ((e.ctrlKey || e.metaKey) && (e.key === "f" || e.key === "F")) {
      e.preventDefault();
      $("#search-input").focus();
      $("#search-input").select();
      return;
    }
    if (typing) {
      if (e.key === "Escape") e.target.blur();
      return;
    }
    // Undo/Redo аннотаций и рисунков
    if ((e.ctrlKey || e.metaKey) && (e.key === "z" || e.key === "Z")) {
      e.preventDefault();
      if (e.shiftKey) redoAnnotation(); else undoAnnotation();
      return;
    }
    if ((e.ctrlKey || e.metaKey) && (e.key === "y" || e.key === "Y")) {
      e.preventDefault(); redoAnnotation(); return;
    }
    if (!state.pdf) return;
    const cur = +$("#page-input").value || 1;
    switch (e.key) {
      case "ArrowRight":
      case "PageDown":
        e.preventDefault(); goToPage(Math.min(state.pdf.numPages, cur + 1)); break;
      case "ArrowLeft":
      case "PageUp":
        e.preventDefault(); goToPage(Math.max(1, cur - 1)); break;
      case "Home":
        e.preventDefault(); goToPage(1); break;
      case "End":
        e.preventDefault(); goToPage(state.pdf.numPages); break;
      case "+":
      case "=":
        e.preventDefault(); setZoom(state.scale + 0.2); break;
      case "-":
        e.preventDefault(); setZoom(state.scale - 0.2); break;
      case "/":
        e.preventDefault(); $("#search-input").focus(); break;
      case "?":
        e.preventDefault(); $("#help-overlay").classList.toggle("hidden"); break;
      case "Escape":
        $("#selection-menu").classList.add("hidden");
        $("#help-overlay").classList.add("hidden"); break;
    }
  });
}

async function sha256(buf) {
  const h = await crypto.subtle.digest("SHA-256", buf);
  return "sha256:" + [...new Uint8Array(h)].map((b) => b.toString(16).padStart(2, "0")).join("");
}

function setStatus(text) {
  const ov = $("#status-overlay");
  ov.classList.remove("hidden");
  ov.innerHTML = `<div class="spinner"></div><span id="status-text"></span>`;
  $("#status-text").textContent = text;
}
function hideStatus() {
  $("#status-overlay").classList.add("hidden");
}

// ---------------------------------------------------------------------------
// Левая панель
// ---------------------------------------------------------------------------

async function buildOutline() {
  const outline = await state.pdf.getOutline();
  const pane = $("#pane-outline");
  pane.innerHTML = "";
  if (!outline.length) {
    pane.innerHTML = '<p class="muted">Структура не найдена в документе.</p>';
    return;
  }
  const render = (items, depth) => {
    for (const it of items) {
      const a = document.createElement("a");
      a.textContent = it.title;
      a.style.paddingLeft = `${4 + depth * 12}px`;
      if (it.page) {
        a.onclick = () => goToPage(it.page);
        a.onmouseenter = (e) => showPreview(it.page, e);
        a.onmousemove = (e) => positionPreview(e);
        a.onmouseleave = hidePreview;
      }
      pane.appendChild(a);
      if (it.children?.length) render(it.children, depth + 1);
    }
  };
  render(outline, 0);
}

// --- Превью страницы при наведении -----------------------------------------

const _previewCache = new Map();
let _previewTimer = null;

function positionPreview(e) {
  const el = $("#page-preview");
  const w = 190;
  let x = e.clientX + 16;
  if (x + w > window.innerWidth) x = e.clientX - w - 16;
  el.style.left = `${x}px`;
  el.style.top = `${Math.min(e.clientY, window.innerHeight - 280)}px`;
}

function showPreview(page, e) {
  positionPreview(e);
  clearTimeout(_previewTimer);
  _previewTimer = setTimeout(async () => {
    const el = $("#page-preview");
    el.innerHTML = "";
    let canvas = _previewCache.get(page);
    if (!canvas) {
      canvas = await state.pdf.pageToCanvas(page - 1, 0.4);
      _previewCache.set(page, canvas);
    }
    el.appendChild(canvas); // cloneNode у canvas теряет содержимое — используем исходный узел
    const num = document.createElement("div");
    num.className = "pp-num";
    num.textContent = `с. ${page}`;
    el.appendChild(num);
    el.classList.remove("hidden");
  }, 180);
}

function hidePreview() {
  clearTimeout(_previewTimer);
  $("#page-preview").classList.add("hidden");
}

function buildThumbnails() {
  const pane = $("#pane-thumbs");
  pane.innerHTML = "";
  // Ленивые миниатюры: плейсхолдеры, canvas рисуется при попадании в видимость.
  const obs = new IntersectionObserver(
    (entries, o) => {
      for (const e of entries) {
        if (!e.isIntersecting) continue;
        const div = e.target;
        o.unobserve(div);
        const n = +div.dataset.page;
        state.pdf.pageToCanvas(n - 1, 0.3).then((canvas) => {
          div.querySelector(".thumb-ph")?.replaceWith(canvas);
        });
      }
    },
    { root: pane, rootMargin: "300px 0px" },
  );

  for (let n = 1; n <= state.pdf.numPages; n++) {
    const vp = state.pdf.baseViewports[n - 1];
    const div = document.createElement("div");
    div.className = "thumb";
    div.dataset.page = n;
    const ph = document.createElement("div");
    ph.className = "thumb-ph";
    ph.style.aspectRatio = `${vp.width} / ${vp.height}`;
    div.appendChild(ph);
    const num = document.createElement("div");
    num.className = "num";
    num.textContent = n;
    div.appendChild(num);
    div.onclick = () => goToPage(n);
    pane.appendChild(div);
    obs.observe(div);
  }
}

// --- Закладки (user + AI) ---------------------------------------------------

function bookmarkKey() {
  return `bookmarks_${state.doc.hash}`;
}
async function loadBookmarks() {
  const { [bookmarkKey()]: list = [] } = await chrome.storage.local.get(bookmarkKey());
  renderBookmarks(list);
}
function renderBookmarks(list) {
  const ul = $("#bookmark-list");
  ul.innerHTML = "";
  for (const b of list) {
    const li = document.createElement("li");
    li.innerHTML = `<span>${b.ai ? '<span class="ai-tag">AI</span> ' : ""}${b.title}</span><span class="muted">с. ${b.page}</span>`;
    li.onclick = () => goToPage(b.page);
    ul.appendChild(li);
  }
}
async function addBookmark(title, page, ai = false) {
  const { [bookmarkKey()]: list = [] } = await chrome.storage.local.get(bookmarkKey());
  list.push({ title, page, ai, ts: Date.now() });
  await chrome.storage.local.set({ [bookmarkKey()]: list });
  renderBookmarks(list);
  pushKey(bookmarkKey());
  collab.broadcast(bookmarkKey(), list);
}

async function generateAiBookmarks() {
  if (!state.doc.pages.length) return;
  const suggested = suggestBookmarks(state.doc.pages);
  const { [bookmarkKey()]: list = [] } = await chrome.storage.local.get(bookmarkKey());
  // Не дублируем уже существующие AI-закладки.
  const have = new Set(list.filter((b) => b.ai).map((b) => `${b.page}:${b.title}`));
  let added = 0;
  for (const b of suggested) {
    if (have.has(`${b.page}:${b.title}`)) continue;
    list.push({ ...b, ts: Date.now() });
    added++;
  }
  await chrome.storage.local.set({ [bookmarkKey()]: list });
  renderBookmarks(list);
  pushKey(bookmarkKey());
  collab.broadcast(bookmarkKey(), list);
  $("#ai-bookmarks").textContent = added ? `✨ Добавлено AI-закладок: ${added}` : "✨ Новых AI-закладок нет";
  setTimeout(() => ($("#ai-bookmarks").textContent = "✨ AI-закладки"), 2500);
}

// --- Сравнение версий: выбор второго PDF и офлайн-дифф ---------------------

async function startCompare() {
  $("#right-panel").classList.remove("collapsed");
  $("#compare-file").click();
}

async function runCompare(file) {
  addMessage("user", `Сравнить с: ${file.name}`);
  const out = addMessage("assistant", "Извлекаю текст второго документа…");
  try {
    const buf = await file.arrayBuffer();
    const other = new PdfController(document.createElement("div"));
    await other.load(buf);
    const pagesB = await other.extractAllText();
    const report = compareDocs(state.doc.pages, pagesB, state.doc.title, file.name);
    setMessageText(out, report);
  } catch (e) {
    setMessageText(out, `⚠ Не удалось сравнить: ${e.message}`);
  }
}

// ---------------------------------------------------------------------------
// Аннотации (М3): выделение / подчёркивание / зачёркивание / заметка
// ---------------------------------------------------------------------------

const ANN_COLORS = { highlight: "#ffd54a", underline: "#3b82f6", strike: "#ef4444", note: "#f59e0b" };

function annKey() {
  return `annotations_${state.doc.hash}`;
}
async function loadAnnotations() {
  const { [annKey()]: list = [] } = await chrome.storage.local.get(annKey());
  state.annotations = list;
  renderCommentsList();
}

const ANN_ICON = { highlight: "🖍", underline: "U̲", strike: "S̶", note: "💬", draw: "✏️" };

function renderCommentsList() {
  const ul = $("#comment-list");
  if (!ul) return;
  const items = [...state.annotations].sort((a, b) => a.page - b.page || a.ts - b.ts);
  if (!items.length) {
    ul.innerHTML = `<li class="cm-empty muted">${t("cm.empty")}</li>`;
    return;
  }
  ul.innerHTML = "";
  for (const a of items) {
    const li = document.createElement("li");
    li.className = "comment-item";
    const main = document.createElement("div");
    main.className = "cm-main";
    main.innerHTML =
      `<span class="cm-page">с. ${a.page}</span> <span class="cm-type">${ANN_ICON[a.type] || ""}</span> ` +
      `<span class="cm-text">${(a.text || "").slice(0, 80) || "—"}</span>` +
      (a.note ? `<div class="cm-note">💬 ${a.note}</div>` : "");
    main.onclick = () => state.pdf.focusHit && goToPage(a.page);
    const del = document.createElement("button");
    del.className = "cm-del";
    del.textContent = "✕";
    del.title = "Удалить";
    del.onclick = (e) => { e.stopPropagation(); removeAnnotation(a.id); };
    li.appendChild(main);
    li.appendChild(del);
    ul.appendChild(li);
  }
}
async function saveAnnotations() {
  await chrome.storage.local.set({ [annKey()]: state.annotations });
  pushKey(annKey());
  collab.broadcast(annKey(), state.annotations);
}

/** Прямоугольники текущего выделения в долях страницы, сгруппированные по страницам. */
function selectionRectsByPage() {
  const sel = window.getSelection();
  if (!sel || sel.isCollapsed || !sel.rangeCount) return null;
  const text = sel.toString().trim();
  const byPage = new Map();
  for (const rect of sel.getRangeAt(0).getClientRects()) {
    if (rect.width < 1 || rect.height < 1) continue;
    const cx = rect.left + rect.width / 2;
    const cy = rect.top + rect.height / 2;
    for (const [num, wrap] of state.pdf.wraps) {
      const b = wrap.getBoundingClientRect();
      if (cx >= b.left && cx <= b.right && cy >= b.top && cy <= b.bottom) {
        const arr = byPage.get(num) || [];
        arr.push({
          x: (rect.left - b.left) / b.width,
          y: (rect.top - b.top) / b.height,
          w: rect.width / b.width,
          h: rect.height / b.height,
        });
        byPage.set(num, arr);
        break;
      }
    }
  }
  return byPage.size ? { byPage, text } : null;
}

async function addAnnotation(type) {
  const res = selectionRectsByPage();
  if (!res) return;
  let note = "";
  if (type === "note") {
    note = window.prompt(t("ann.note.prompt")) || "";
    if (!note) return;
  }
  for (const [page, rects] of res.byPage) {
    state.annotations.push({
      id: `${page}-${state.annotations.length}-${rects[0].x.toFixed(4)}`,
      page, type, rects, color: ANN_COLORS[type], text: res.text.slice(0, 200), note, ts: Date.now(),
    });
  }
  state.redoStack = [];
  await saveAnnotations();
  window.getSelection().removeAllRanges();
  for (const page of res.byPage.keys()) renderAnnotationsForPage(page, state.pdf.wraps.get(page));
  renderCommentsList();
}

async function removeAnnotation(id) {
  state.annotations = state.annotations.filter((a) => a.id !== id);
  await saveAnnotations();
  document.querySelectorAll(`[data-ann="${id}"]`).forEach((el) => el.remove());
  renderCommentsList();
}

/** Откат последней добавленной аннотации/рисунка (Ctrl+Z). */
async function undoAnnotation() {
  if (!state.annotations.length) return;
  const a = state.annotations.pop();
  state.redoStack.push(a);
  await saveAnnotations();
  renderAnnotationsForPage(a.page, state.pdf.wraps.get(a.page));
  renderCommentsList();
}
/** Повтор отменённого (Ctrl+Y / Ctrl+Shift+Z). */
async function redoAnnotation() {
  if (!state.redoStack.length) return;
  const a = state.redoStack.pop();
  state.annotations.push(a);
  await saveAnnotations();
  renderAnnotationsForPage(a.page, state.pdf.wraps.get(a.page));
  renderCommentsList();
}

const ANN_LABELS = () => ({
  highlight: t("annx.highlight"), underline: t("annx.underline"), strike: t("annx.strike"), note: t("annx.note"), draw: t("annx.draw"),
});

function exportAnnotations() {
  const anns = [...state.annotations].sort((a, b) => a.page - b.page || a.ts - b.ts);
  if (!anns.length) {
    alert("Аннотаций нет — сначала выделите текст и добавьте заметку/выделение.");
    return;
  }
  const labels = ANN_LABELS();
  let md = `# Аннотации — ${state.doc.title || "документ"}\n\n`;
  let lastPage = null;
  for (const a of anns) {
    if (a.page !== lastPage) { md += `\n## Страница ${a.page}\n`; lastPage = a.page; }
    md += `- **${labels[a.type] || a.type}:** ${(a.text || "").trim()}`;
    if (a.note) md += `\n  - 💬 _${a.note}_`;
    md += "\n";
  }
  const blob = new Blob([md], { type: "text/markdown;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `${(state.doc.title || "document").replace(/\.pdf$/i, "")}.annotations.md`;
  a.click();
  setTimeout(() => URL.revokeObjectURL(url), 5000);
}

// --- Рисование (карандаш, М3) ----------------------------------------------

const SVGNS = "http://www.w3.org/2000/svg";

/** Рисует фигуру (pencil/line/rect/arrow) в svg по точкам в пикселях. */
function renderDrawInto(svg, shape, pts, color, width) {
  while (svg.firstChild) svg.removeChild(svg.firstChild);
  const mk = (tag, attrs) => { const el = document.createElementNS(SVGNS, tag); for (const k in attrs) el.setAttribute(k, attrs[k]); return el; };
  const stroke = { fill: "none", stroke: color, "stroke-width": width, "stroke-linejoin": "round", "stroke-linecap": "round" };
  const a = pts[0], b = pts[pts.length - 1];
  if (shape === "rect" && pts.length >= 2) {
    svg.appendChild(mk("rect", { ...stroke, x: Math.min(a[0], b[0]), y: Math.min(a[1], b[1]), width: Math.abs(b[0] - a[0]), height: Math.abs(b[1] - a[1]) }));
  } else if ((shape === "line" || shape === "arrow") && pts.length >= 2) {
    svg.appendChild(mk("line", { ...stroke, x1: a[0], y1: a[1], x2: b[0], y2: b[1] }));
    if (shape === "arrow") {
      const ang = Math.atan2(b[1] - a[1], b[0] - a[0]); const len = Math.max(9, width * 4);
      const h1 = [b[0] - len * Math.cos(ang - 0.45), b[1] - len * Math.sin(ang - 0.45)];
      const h2 = [b[0] - len * Math.cos(ang + 0.45), b[1] - len * Math.sin(ang + 0.45)];
      svg.appendChild(mk("polygon", { fill: color, stroke: color, points: `${b[0]},${b[1]} ${h1[0].toFixed(1)},${h1[1].toFixed(1)} ${h2[0].toFixed(1)},${h2[1].toFixed(1)}` }));
    }
  } else {
    svg.appendChild(mk("polyline", { ...stroke, points: pts.map(([x, y]) => `${x.toFixed(1)},${y.toFixed(1)}`).join(" ") }));
  }
}

function setupDrawing() {
  const pages = $("#pages");
  let cur = null;
  const norm = (e, b) => [(e.clientX - b.left) / b.width, (e.clientY - b.top) / b.height];
  const px = (pts, b) => pts.map(([x, y]) => [x * b.width, y * b.height]);
  const eraseAt = (e) => {
    const svg = document.elementFromPoint(e.clientX, e.clientY)?.closest?.(".ann-draw-svg");
    if (svg?.dataset.ann) removeAnnotation(svg.dataset.ann);
  };
  pages.addEventListener("pointerdown", (e) => {
    if (!state.drawing) return;
    const wrap = e.target.closest(".page-wrap");
    if (!wrap) return;
    e.preventDefault();
    if (state.drawShape === "erase") { cur = { erase: true }; eraseAt(e); return; }
    const b = wrap.getBoundingClientRect();
    cur = { page: +wrap.dataset.page, b, shape: state.drawShape, pts: [norm(e, b)] };
    cur.svg = document.createElementNS(SVGNS, "svg");
    cur.svg.setAttribute("class", "ann-draw-svg live");
    wrap.appendChild(cur.svg);
    try { pages.setPointerCapture?.(e.pointerId); } catch { /* синтетический указатель */ }
  });
  pages.addEventListener("pointermove", (e) => {
    if (!cur) return;
    if (cur.erase) { eraseAt(e); return; }
    if (cur.shape === "pencil") cur.pts.push(norm(e, cur.b));
    else cur.pts = [cur.pts[0], norm(e, cur.b)];
    renderDrawInto(cur.svg, cur.shape, px(cur.pts, cur.b), state.drawColor, state.drawWidth);
  });
  const finish = async () => {
    if (!cur) return;
    const c = cur; cur = null;
    if (c.erase) return;
    c.svg.remove();
    const moved = c.pts.length > 1 && (c.shape !== "pencil" ? Math.hypot(c.pts[0][0] - c.pts.at(-1)[0], c.pts[0][1] - c.pts.at(-1)[1]) > 0.005 : true);
    if (moved) {
      state.annotations.push({
        id: `d-${c.page}-${state.annotations.length}-${c.pts.length}`,
        page: c.page, type: "draw", shape: c.shape, points: c.pts, color: state.drawColor, width: state.drawWidth, text: t(`draw.${c.shape}`), ts: Date.now(),
      });
      state.redoStack = [];
      await saveAnnotations();
      renderAnnotationsForPage(c.page, state.pdf.wraps.get(c.page));
      renderCommentsList();
    }
  };
  pages.addEventListener("pointerup", finish);
  pages.addEventListener("pointercancel", finish);
}

function toggleDraw() {
  state.drawing = !state.drawing;
  $("#pages").classList.toggle("drawing", state.drawing);
  $("#btn-draw").classList.toggle("active", state.drawing);
}

function renderAnnotationsForPage(num, wrap) {
  if (!wrap) return;
  wrap.querySelectorAll(".ann-layer").forEach((el) => el.remove());
  const items = state.annotations.filter((a) => a.page === num);
  if (!items.length) return;
  const layer = document.createElement("div");
  layer.className = "ann-layer";
  const W = wrap.clientWidth || parseFloat(wrap.style.width);
  const H = wrap.clientHeight || parseFloat(wrap.style.height);
  for (const a of items) {
    if (a.type === "draw") {
      const svg = document.createElementNS(SVGNS, "svg");
      svg.setAttribute("class", "ann-draw-svg");
      svg.dataset.ann = a.id;
      renderDrawInto(svg, a.shape || "pencil", (a.points || []).map(([x, y]) => [x * W, y * H]), a.color || "#ef4444", a.width || 2);
      svg.querySelectorAll("*").forEach((el) => (el.style.pointerEvents = "stroke"));
      svg.oncontextmenu = (e) => { e.preventDefault(); if (confirm("Удалить рисунок?")) removeAnnotation(a.id); };
      layer.appendChild(svg);
      continue;
    }
    for (const r of a.rects || []) {
      const el = document.createElement("div");
      el.className = `ann ann-${a.type}`;
      el.dataset.ann = a.id;
      el.style.left = `${r.x * 100}%`;
      el.style.top = `${r.y * 100}%`;
      el.style.width = `${r.w * 100}%`;
      el.style.height = `${r.h * 100}%`;
      if (a.type === "highlight") el.style.background = a.color;
      if (a.type === "underline") el.style.borderBottom = `2px solid ${a.color}`;
      if (a.type === "strike") el.style.setProperty("--strike", a.color);
      if (a.note) { el.title = a.note; el.classList.add("ann-has-note"); }
      el.oncontextmenu = (e) => { e.preventDefault(); if (confirm("Удалить аннотацию?")) removeAnnotation(a.id); };
      layer.appendChild(el);
    }
    if (a.type === "note") {
      const pin = document.createElement("div");
      pin.className = "ann-note-pin";
      pin.dataset.ann = a.id;
      pin.textContent = "💬";
      pin.title = a.note;
      pin.style.left = `${a.rects[0].x * 100}%`;
      pin.style.top = `${a.rects[0].y * 100}%`;
      pin.onclick = () => alert(a.note);
      pin.oncontextmenu = (e) => { e.preventDefault(); if (confirm("Удалить заметку?")) removeAnnotation(a.id); };
      layer.appendChild(pin);
    }
  }
  wrap.appendChild(layer);
}

// ---------------------------------------------------------------------------
// Навигация / зум / поиск
// ---------------------------------------------------------------------------

function goToPage(n) {
  onPageChange(n);
  if (state.viewMode === "single") showSinglePage(n);
  else state.pdf.scrollToPage(n);
}

async function setZoom(scale, keepFit = false) {
  if (!keepFit) state.fitMode = null;
  state.scale = Math.max(0.25, Math.min(5, scale));
  $("#zoom-level").textContent = `${Math.round(state.scale * 100)}%`;
  await state.pdf.setScale(state.scale);
}

/** Масштаб «по ширине»/«целиком» от размеров контейнера и текущей страницы. */
function computeFitScale(mode) {
  if (!state.pdf) return state.scale;
  const cur = +$("#page-input").value || 1;
  const vp = state.pdf.baseViewports[cur - 1] || state.pdf.baseViewports[0];
  if (!vp) return state.scale;
  const swap = state.pdf.rotation % 180 !== 0;
  const pw = swap ? vp.height : vp.width;
  const ph = swap ? vp.width : vp.height;
  const c = $("#viewer-container");
  const availW = c.clientWidth - 36;
  const availH = c.clientHeight - 36;
  const sW = availW / pw;
  return mode === "page" ? Math.min(sW, availH / ph) : sW;
}
async function applyFit() {
  if (!state.fitMode) return;
  await setZoom(computeFitScale(state.fitMode), true);
}
async function setFit(mode) {
  state.fitMode = mode;
  await setZoom(computeFitScale(mode), true);
}

/** Узкое окно: автоматически сворачиваем боковые панели (раз при пересечении порога). */
function applyResponsive() {
  const narrow = window.innerWidth < 820;
  if (narrow === state._narrow) return;
  state._narrow = narrow;
  $("#left-panel").classList.toggle("collapsed", narrow);
  $("#right-panel").classList.toggle("collapsed", narrow);
}

function runSearch(query) {
  const { pages, total, error } = state.pdf.search(query, state.searchOpts);
  state.searchHits = pages;
  state.searchIdx = -1;
  state.searchTotal = total;
  $("#search-count").textContent = error ? "⚠ regex" : total ? `${total} на ${pages.length} стр.` : "0";
  if (pages.length) nextHit(1);
}
function nextHit(dir) {
  if (!state.searchHits.length) return;
  state.searchIdx = (state.searchIdx + dir + state.searchHits.length) % state.searchHits.length;
  const page = state.searchHits[state.searchIdx];
  state.pdf.focusHit(page);
  onPageChange(page);
  $("#search-count").textContent = `стр. ${state.searchIdx + 1}/${state.searchHits.length} (всего ${state.searchTotal})`;
}

// ---------------------------------------------------------------------------
// AI-панель
// ---------------------------------------------------------------------------

function buildQuickActions() {
  const wrap = $("#quick-actions");
  wrap.innerHTML = "";
  for (const a of QUICK_ACTIONS) {
    const btn = document.createElement("button");
    btn.className = "qa-btn";
    btn.textContent = quickActionLabel(a, getLang());
    btn.onclick = a.id === "compare" ? startCompare : () => sendToAI(a.prompt, a.id);
    wrap.appendChild(btn);
  }
}

async function buildProfileSelect() {
  const sel = $("#profile-select");
  const s = await getSettings();
  sel.innerHTML = "";
  for (const p of profileList(getLang())) {
    const opt = document.createElement("option");
    opt.value = p.id;
    opt.textContent = p.label;
    if (p.id === s.profile) opt.selected = true;
    sel.appendChild(opt);
  }
  sel.onchange = () => setSettings({ profile: sel.value });
}

const chatHistory = []; // [{role, content}]

function addMessage(role, text) {
  const div = document.createElement("div");
  div.className = `msg ${role}`;
  $("#chat-messages").appendChild(div);
  $("#chat-messages").scrollTop = $("#chat-messages").scrollHeight;
  if (text) setMessageText(div, text);
  return div;
}

function setMessageText(div, text) {
  // Превращаем [с. N] в кликабельные ссылки.
  div.innerHTML = "";
  const re = /\[с\.\s*(\d+)[^\]]*\]/g;
  let last = 0;
  let m;
  while ((m = re.exec(text))) {
    div.appendChild(document.createTextNode(text.slice(last, m.index)));
    const a = document.createElement("span");
    a.className = "cite";
    a.textContent = m[0];
    const page = +m[1];
    a.onclick = () => goToPage(page);
    div.appendChild(a);
    last = m.index + m[0].length;
  }
  div.appendChild(document.createTextNode(text.slice(last)));
  $("#chat-messages").scrollTop = $("#chat-messages").scrollHeight;
}

async function sendToAI(prompt, intent = null) {
  if (!state.doc.pages.length) {
    addMessage("assistant", t("doc.loading"));
    return;
  }
  if (state.abort) state.abort.abort();
  state.abort = new AbortController();

  addMessage("user", prompt);
  chatHistory.push({ role: "user", content: prompt });
  const out = addMessage("assistant", "");
  let acc = "";
  $("#chat-send").disabled = true;
  $("#ai-meta").textContent = t("ai.typing");

  try {
    await ask(
      { doc: state.doc, messages: chatHistory, profileId: $("#profile-select").value, intent },
      (delta) => {
        acc += delta;
        setMessageText(out, acc);
      },
      state.abort.signal,
    );
    chatHistory.push({ role: "assistant", content: acc });
    await pushHistory("questions", { docHash: state.doc.hash, q: prompt, a: acc });
    $("#ai-meta").textContent = "";
  } catch (e) {
    setMessageText(out, `⚠ Ошибка AI: ${e.message}\n\nПроверьте настройки провайдера (⚙).`);
    $("#ai-meta").textContent = "";
  } finally {
    $("#chat-send").disabled = false;
    state.abort = null;
  }
}

// ---------------------------------------------------------------------------
// Контекстное меню над выделением (внутри viewer)
// ---------------------------------------------------------------------------

function setupSelectionMenu() {
  const menu = $("#selection-menu");
  const actions = ["explain", "translate", "shorten", "rewrite", "risks", "ask"].map((id) => [id, t(`sel.${id}`)]);
  const annActions = ["highlight", "underline", "strike", "note"].map((id) => [id, t(`sel.${id}`)]);

  document.addEventListener("mouseup", (e) => {
    if (menu.contains(e.target)) return;
    const sel = window.getSelection().toString().trim();
    if (sel.length < 3) {
      menu.classList.add("hidden");
      return;
    }
    menu.innerHTML = "";
    for (const [id, label] of actions) {
      const b = document.createElement("button");
      b.textContent = label;
      b.onclick = () => {
        menu.classList.add("hidden");
        $("#right-panel").classList.remove("collapsed");
        sendToAI(SELECTION_PROMPTS[id](sel), id);
      };
      menu.appendChild(b);
    }
    const sep = document.createElement("div");
    sep.className = "menu-sep";
    menu.appendChild(sep);
    for (const [id, label] of annActions) {
      const b = document.createElement("button");
      b.textContent = label;
      // mousedown, чтобы не потерять выделение до обработки
      b.onmousedown = (ev) => {
        ev.preventDefault();
        addAnnotation(id);
        menu.classList.add("hidden");
      };
      menu.appendChild(b);
    }
    menu.style.left = `${Math.min(e.clientX, window.innerWidth - 160)}px`;
    menu.style.top = `${e.clientY + 8}px`;
    menu.classList.remove("hidden");
  });

  document.addEventListener("mousedown", (e) => {
    if (!menu.contains(e.target)) menu.classList.add("hidden");
  });

  // Действия из контекстного меню браузера (background.js).
  chrome.runtime.onMessage.addListener((msg) => {
    if (msg?.type === "selection-action" && msg.text) {
      $("#right-panel").classList.remove("collapsed");
      const fn = SELECTION_PROMPTS[msg.action] || SELECTION_PROMPTS.ask;
      sendToAI(fn(msg.text), msg.action);
    }
  });
}

// ---------------------------------------------------------------------------
// Привязка элементов UI
// ---------------------------------------------------------------------------

function setupUI() {
  applyI18n();
  buildQuickActions();
  buildProfileSelect();
  setupSelectionMenu();
  setupKeyboard();
  applyTheme();
  applyInvert();
  applyViewMode();
  $("#view-mode").onchange = async () => {
    await setSettings({ viewMode: $("#view-mode").value });
    setViewMode($("#view-mode").value);
  };

  // Tabs
  document.querySelectorAll(".tab").forEach((tab) => {
    tab.onclick = () => {
      document.querySelectorAll(".tab").forEach((t) => { t.classList.remove("active"); t.setAttribute("aria-selected", "false"); });
      document.querySelectorAll(".tab-pane").forEach((p) => p.classList.remove("active"));
      tab.classList.add("active");
      tab.setAttribute("aria-selected", "true");
      $(`#pane-${tab.dataset.tab}`).classList.add("active");
    };
  });
  setupA11y();

  // Панели
  $("#btn-toggle-left").onclick = () => $("#left-panel").classList.toggle("collapsed");
  $("#btn-toggle-right").onclick = () => $("#right-panel").classList.toggle("collapsed");

  // Зум
  $("#zoom-in").onclick = () => setZoom(state.scale + 0.2);
  $("#zoom-out").onclick = () => setZoom(state.scale - 0.2);
  $("#fit-width").onclick = () => setFit("width");
  $("#fit-page").onclick = () => setFit("page");
  let _resizeTimer = null;
  window.addEventListener("resize", () => { clearTimeout(_resizeTimer); _resizeTimer = setTimeout(() => { applyResponsive(); applyFit(); }, 200); });
  window.addEventListener("pagehide", () => collab.disconnect());
  applyResponsive();

  // Страница
  $("#page-input").onchange = (e) => goToPage(+e.target.value);

  // Поиск
  let searchTimer;
  $("#search-input").oninput = (e) => {
    clearTimeout(searchTimer);
    searchTimer = setTimeout(() => runSearch(e.target.value), 250);
  };
  $("#search-next").onclick = () => nextHit(1);
  $("#search-prev").onclick = () => nextHit(-1);
  $("#search-input").onkeydown = (e) => { if (e.key === "Enter") nextHit(e.shiftKey ? -1 : 1); };
  const opt = (id, key) => {
    $(id).onclick = () => {
      state.searchOpts[key] = !state.searchOpts[key];
      $(id).classList.toggle("active", state.searchOpts[key]);
      const q = $("#search-input").value;
      if (q) runSearch(q);
    };
  };
  opt("#search-case", "caseSensitive");
  opt("#search-word", "wholeWord");
  opt("#search-regex", "regex");

  // Кнопки топбара
  $("#btn-download").onclick = () =>
    chrome.runtime.sendMessage({ type: "download-pdf", url: state.fileUrl, filename: state.doc.title });
  $("#btn-print").onclick = async () => {
    if (!state.pdf) return;
    setStatus(t("st.printprep"));
    await state.pdf.renderAllForPrint();
    hideStatus();
    window.print();
  };
  $("#btn-newwindow").onclick = () =>
    chrome.runtime.sendMessage({ type: "open-window", url: location.href });
  $("#btn-fullscreen").onclick = () =>
    document.fullscreenElement ? document.exitFullscreen() : $("#viewer-container").requestFullscreen();
  $("#btn-theme").onclick = cycleTheme;
  setupDrawing();
  $("#btn-draw").onclick = toggleDraw;
  $("#draw-color").onchange = (e) => { state.drawColor = e.target.value; };
  $("#draw-shape").onchange = (e) => { state.drawShape = e.target.value; if (!state.drawing) toggleDraw(); };
  $("#draw-width").onchange = (e) => { state.drawWidth = +e.target.value; };
  $("#btn-rotate").onclick = async () => {
    if (!state.pdf) return;
    await state.pdf.setRotation(90);
    if (state.doc.hash) chrome.storage.local.set({ [`rotation_${state.doc.hash}`]: state.pdf.rotation });
  };
  $("#btn-invert").onclick = toggleInvert;
  $("#help-close").onclick = () => $("#help-overlay").classList.add("hidden");
  $("#btn-ai-settings").onclick = () => chrome.runtime.sendMessage({ type: "open-options" });

  // Закладки
  $("#add-bookmark").onclick = () => {
    const page = +$("#page-input").value || 1;
    const title = window.getSelection().toString().trim().slice(0, 60) || `Страница ${page}`;
    addBookmark(title, page, false);
  };
  $("#ai-bookmarks").onclick = generateAiBookmarks;
  $("#export-annotations").onclick = exportAnnotations;
  $("#ocr-run").onclick = runOcrNow;
  $("#ocr-dismiss").onclick = () => $("#ocr-banner").classList.add("hidden");

  // Сравнение версий
  $("#compare-file").onchange = (e) => {
    const file = e.target.files?.[0];
    if (file) runCompare(file);
    e.target.value = "";
  };

  // Чат
  $("#chat-send").onclick = () => {
    const text = $("#chat-text").value.trim();
    if (text) {
      $("#chat-text").value = "";
      sendToAI(text);
    }
  };
  $("#chat-text").onkeydown = (e) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      $("#chat-send").click();
    }
  };
}

boot();
