(function () {
  "use strict";
  var tenant = null;

  function api(p, o) { return fetch(p, Object.assign({ credentials: "same-origin" }, o)); }
  function $(id) { return document.getElementById(id); }
  function esc(s) { return String(s == null ? "" : s).replace(/[&<>"']/g, function (c) { return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]; }); }
  function fmtSize(b) { if (!b) return ""; var mb = b / 1048576; return mb >= 1 ? mb.toFixed(1) + " MB" : Math.max(1, Math.round(b / 1024)) + " KB"; }
  function ago(ts) { if (!ts) return "—"; var s = (Date.now() - ts) / 1000; if (s < 60) return "just now"; if (s < 3600) return Math.floor(s / 60) + "m ago"; if (s < 86400) return Math.floor(s / 3600) + "h ago"; return Math.floor(s / 86400) + "d ago"; }

  var toastBox = $("toasts");
  function toast(m, k) { k = k || "info"; var t = document.createElement("div"); t.className = "toast " + k; t.innerHTML = '<span class="ti">' + (k === "ok" ? "✓" : k === "err" ? "✕" : "i") + "</span><span>" + esc(m) + "</span>"; toastBox.appendChild(t); setTimeout(function () { t.classList.add("out"); setTimeout(function () { t.remove(); }, 280); }, 3400); }

  // ── markdown (for AI messages) ──
  function mdInline(s) {
    s = esc(s);
    s = s.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+|mailto:[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
    s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>").replace(/__([^_]+)__/g, "<strong>$1</strong>");
    s = s.replace(/`([^`]+)`/g, "<code>$1</code>");
    s = s.replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g, "$1<em>$2</em>");
    return s;
  }
  function md(src) {
    var lines = String(src).split("\n"), html = "", list = null;
    function close() { if (list) { html += "</" + list + ">"; list = null; } }
    for (var i = 0; i < lines.length; i++) {
      var line = lines[i].replace(/\s+$/, "");
      var ul = /^\s*[-*]\s+(.*)$/.exec(line), ol = /^\s*(\d+)[.)]\s+(.*)$/.exec(line);
      if (ul) { if (list !== "ul") { close(); html += "<ul>"; list = "ul"; } html += "<li>" + mdInline(ul[1]) + "</li>"; }
      else if (ol) { if (list !== "ol") { close(); html += "<ol>"; list = "ol"; } html += '<li value="' + ol[1] + '">' + mdInline(ol[2]) + "</li>"; }
      else if (line.trim() === "") continue;
      else { close(); html += "<div>" + mdInline(line) + "</div>"; }
    }
    close(); return html;
  }

  // ── auth ──
  var authView = $("authView"), app = $("app");
  function setAuthed(a, t) {
    authView.classList.toggle("hidden", a);
    app.classList.toggle("hidden", !a);
    if (a) { tenant = t; applyTenant(t); loadDocs(); startConvPolling(); }
    else stopConvPolling();
  }
  function applyTenant(t) {
    if (!t) return;
    $("uName").textContent = t.name;
    $("uEmail").textContent = t.adminEmail;
    $("uAv").textContent = (t.name || "?").charAt(0).toUpperCase();
    $("pausedBanner").classList.toggle("hidden", t.status === "active");
    var origin = location.origin;
    $("embedCode").textContent = '<script src="' + origin + '/widget.js" data-tenant="' + t.publicKey + '"><' + "/script>";
    $("keyView").textContent = t.publicKey;
    var s = t.settings || {};
    $("setName").value = s.assistantName || "";
    $("setGreeting").value = s.greeting || "";
    $("setAccent").value = s.accentColor || "#6366f1";
    $("setPrompt").value = s.systemPrompt || "";
    $("setNotify").value = s.notifyEmail || "";
    $("setOpenai").value = "";
    $("oaiState").textContent = s.openaiKeySet ? "· a key is configured" : "· using platform key";
    var sm = s.smtp || {};
    $("smtpHost").value = sm.host || ""; $("smtpPort").value = sm.port || ""; $("smtpUser").value = sm.user || ""; $("smtpFrom").value = sm.from || ""; $("smtpSecure").checked = !!sm.secure; $("smtpPass").value = "";
    $("smtpState").textContent = sm.passSet ? "· set" : "";
  }

  api("/api/me").then(function (r) { return r.json(); }).then(function (s) { setAuthed(s.authed, s.tenant); }).catch(function () { setAuthed(false); });

  $("authForm").addEventListener("submit", function (e) {
    e.preventDefault();
    var b = $("authBtn"); b.disabled = true; b.textContent = "Signing in…";
    api("/api/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: $("au-email").value, password: $("au-pass").value }) })
      .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })
      .then(function (res) {
        b.disabled = false; b.textContent = "Sign in";
        if (res.ok) api("/api/me").then(function (r) { return r.json(); }).then(function (s) { setAuthed(true, s.tenant); toast("Signed in", "ok"); });
        else { document.querySelector(".auth-card").classList.add("shake"); setTimeout(function () { document.querySelector(".auth-card").classList.remove("shake"); }, 450); toast(res.d.error || "Login failed", "err"); }
      }).catch(function () { b.disabled = false; b.textContent = "Sign in"; toast("Login failed", "err"); });
  });

  $("forgotLink").addEventListener("click", function () {
    var email = $("au-email").value.trim();
    if (!email) { $("au-email").focus(); toast("Enter your email above, then click again", "info"); return; }
    api("/api/forgot", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: email }) })
      .then(function (r) { return r.json(); })
      .then(function (d) { if (d.devLink) { console.log("Password reset link:", d.devLink); toast("Testing mode — reset link in console", "info"); } else toast("If that email exists, we've sent a reset link.", "ok"); })
      .catch(function () { toast("Something went wrong", "err"); });
  });

  $("logout").addEventListener("click", function () { api("/api/logout", { method: "POST" }).then(function () { setAuthed(false); toast("Signed out", "info"); }); });

  // ── nav ──
  var VIEWS = { kb: ["Knowledge base", "The docs your assistant answers from."], convos: ["Conversations", "Chat live with your visitors."], install: ["Install", "Add the widget to your site."], settings: ["Settings", "Branding, OpenAI key, and email."] };
  document.querySelectorAll("#nav a").forEach(function (a) {
    a.addEventListener("click", function () {
      document.querySelectorAll("#nav a").forEach(function (x) { x.classList.remove("on"); });
      a.classList.add("on");
      var v = a.getAttribute("data-view");
      Object.keys(VIEWS).forEach(function (n) { $("view-" + n).classList.toggle("hidden", n !== v); });
      $("pageTitle").textContent = VIEWS[v][0]; $("pageSub").textContent = VIEWS[v][1];
      if (v === "convos") loadConvos();
    });
  });

  // ── KB: documents ──
  var docsEl = $("docs"), pollDocs = null;
  function skeleton() { var h = ""; for (var i = 0; i < 2; i++) h += '<div class="sk"><div class="b sq"></div><div style="flex:1"><div class="b l1"></div><div class="b l2"></div></div></div>'; docsEl.innerHTML = h; }
  function loadDocs() { if (!docsEl.children.length) skeleton(); api("/admin/documents").then(function (r) { return r.json(); }).then(function (d) { renderDocs(d.documents || []); }).catch(function () {}); }
  var EMPTY_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5a2 2 0 0 1 2-2h6l2 2h4a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/></svg>';
  var TRASH = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13"/></svg>';
  function renderDocs(list) {
    $("stTotal").textContent = list.length;
    $("stReady").textContent = list.filter(function (x) { return x.status === "completed"; }).length;
    if (!list.length) { docsEl.innerHTML = '<div class="empty"><div class="ei">' + EMPTY_ICON + "</div><p>No documents yet. Crawl your site or upload a PDF.</p></div>"; }
    else {
      docsEl.innerHTML = list.map(function (doc) {
        var ready = doc.status === "completed", isSite = /^site-/.test(doc.filename);
        return '<div class="item"><div class="fico ' + (isSite ? "web" : "pdf") + '">' + (isSite ? "WEB" : "PDF") + '</div><div class="info"><div class="nm">' + esc(doc.filename) + '</div><div class="mt">' + fmtSize(doc.bytes) + '</div></div><span class="pill ' + (ready ? "ready" : "pending") + '"><span class="pd"></span>' + (ready ? "Ready" : "Indexing") + '</span><button class="icobtn" data-id="' + doc.id + '">' + TRASH + "</button></div>";
      }).join("");
      docsEl.querySelectorAll("button[data-id]").forEach(function (b) { b.addEventListener("click", function () { delDoc(b.getAttribute("data-id"), b); }); });
    }
    var pending = list.some(function (x) { return x.status !== "completed"; });
    clearTimeout(pollDocs); if (pending) pollDocs = setTimeout(loadDocs, 2500);
  }
  function delDoc(id, btn) { if (!confirm("Remove this document?")) return; btn.disabled = true; api("/admin/documents/" + id, { method: "DELETE" }).then(function (r) { return r.json(); }).then(function () { toast("Document removed", "ok"); loadDocs(); }).catch(function () { btn.disabled = false; toast("Delete failed", "err"); }); }

  // ── KB: crawl ──
  var crawlBtn = $("crawlBtn");
  crawlBtn.addEventListener("click", function () {
    var url = $("crawlUrl").value.trim(); if (!url) { toast("Enter a URL to crawl", "err"); return; }
    crawlBtn.disabled = true; crawlBtn.textContent = "Crawling…"; toast("Crawling " + url + " — this can take a minute…", "info");
    api("/admin/crawl", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: url, maxPages: Number($("crawlMax").value) }) })
      .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })
      .then(function (res) { crawlBtn.disabled = false; crawlBtn.textContent = "Crawl"; if (res.ok) { toast("Crawled " + res.d.pages + " pages", "ok"); loadDocs(); } else toast(res.d.error || "Crawl failed", "err"); })
      .catch(function () { crawlBtn.disabled = false; crawlBtn.textContent = "Crawl"; toast("Crawl failed", "err"); });
  });

  // ── KB: upload ──
  var drop = $("drop"), fileInput = $("file"), prog = $("prog");
  drop.addEventListener("click", function () { fileInput.click(); });
  fileInput.addEventListener("change", function () { upload(fileInput.files); fileInput.value = ""; });
  ["dragenter", "dragover"].forEach(function (ev) { drop.addEventListener(ev, function (e) { e.preventDefault(); drop.classList.add("over"); }); });
  ["dragleave", "drop"].forEach(function (ev) { drop.addEventListener(ev, function (e) { e.preventDefault(); if (ev === "dragleave" && drop.contains(e.relatedTarget)) return; drop.classList.remove("over"); }); });
  drop.addEventListener("drop", function (e) { if (e.dataTransfer.files.length) upload(e.dataTransfer.files); });
  function upload(files) {
    var fd = new FormData(), n = 0;
    for (var i = 0; i < files.length; i++) if (files[i].type === "application/pdf" || /\.pdf$/i.test(files[i].name)) { fd.append("files", files[i]); n++; }
    if (!n) { toast("Please choose PDF files", "err"); return; }
    prog.classList.add("show"); toast("Uploading " + n + " file" + (n > 1 ? "s" : "") + "…", "info");
    api("/admin/upload", { method: "POST", body: fd }).then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })
      .then(function (res) { prog.classList.remove("show"); if (res.ok) { toast("Indexed " + res.d.indexed + "/" + res.d.uploaded, res.d.failed ? "info" : "ok"); loadDocs(); } else toast(res.d.error || "Upload failed", "err"); })
      .catch(function () { prog.classList.remove("show"); toast("Upload failed", "err"); });
  }

  // ── install ──
  $("copyEmbed").addEventListener("click", function () { navigator.clipboard.writeText($("embedCode").textContent).then(function () { toast("Snippet copied", "ok"); }, function () { toast("Copy failed", "err"); }); });

  // ── settings ──
  $("saveSettings").addEventListener("click", function () {
    var b = this; b.disabled = true; b.textContent = "Saving…";
    var body = {
      assistantName: $("setName").value, greeting: $("setGreeting").value, accentColor: $("setAccent").value,
      systemPrompt: $("setPrompt").value, notifyEmail: $("setNotify").value,
      smtp: { host: $("smtpHost").value, port: $("smtpPort").value, user: $("smtpUser").value, from: $("smtpFrom").value, secure: $("smtpSecure").checked },
    };
    if ($("setOpenai").value.trim()) body.openaiKey = $("setOpenai").value.trim();
    if ($("smtpPass").value) body.smtp.pass = $("smtpPass").value;
    api("/admin/settings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) })
      .then(function (r) { return r.json(); })
      .then(function (d) { b.disabled = false; b.textContent = "Save changes"; if (d.ok) { tenant = d.tenant; applyTenant(d.tenant); toast("Settings saved", "ok"); } else toast("Save failed", "err"); })
      .catch(function () { b.disabled = false; b.textContent = "Save changes"; toast("Save failed", "err"); });
  });

  // ── conversations ──
  var convPoll = null, threadPoll = null, currentConv = null;
  function startConvPolling() { if (!convPoll) { pollBadge(); convPoll = setInterval(pollBadge, 5000); } }
  function stopConvPolling() { clearInterval(convPoll); convPoll = null; clearInterval(threadPoll); threadPoll = null; }
  function pollBadge() {
    api("/admin/conversations").then(function (r) { return r.ok ? r.json() : null; }).then(function (d) {
      if (!d) return;
      var need = d.conversations.filter(function (c) { return c.handoffRequested && c.mode !== "human"; }).length;
      var badge = $("navBadge"); badge.textContent = need; badge.classList.toggle("show", need > 0);
      if (!$("view-convos").classList.contains("hidden")) renderConvos(d.conversations); // keeps the list fresh alongside the open thread
    }).catch(function () {});
  }
  function loadConvos() { api("/admin/conversations").then(function (r) { return r.json(); }).then(function (d) { renderConvos(d.conversations); }).catch(function () {}); }
  function renderConvos(list) {
    var el = $("convList");
    if (!list.length) { el.innerHTML = '<div class="empty"><div class="ei">' + EMPTY_ICON + "</div><p>No conversations yet.</p></div>"; return; }
    el.innerHTML = list.map(function (c) {
      var tag = c.status === "closed" ? '<span class="tag closed">Closed</span>' : c.mode === "human" ? '<span class="tag live">Live</span>' : c.handoffRequested ? '<span class="tag human">Needs human</span>' : "";
      var unread = c.agentUnread ? '<span class="cunread">' + c.agentUnread + "</span>" : "";
      var last = c.last ? (c.last.role === "user" ? "" : c.last.role === "agent" ? "You: " : c.last.role === "system" ? "" : "AI: ") + c.last.text : "";
      var active = c.id === currentConv ? " active" : "";
      return '<div class="conv' + active + '" data-id="' + c.id + '"><div class="av">' + esc((c.name || "?").charAt(0).toUpperCase()) + '</div><div class="ci"><div class="cr"><span class="cn">' + esc(c.name || "Visitor") + '</span>' + tag + '</div><div class="cl">' + esc(last).slice(0, 70) + '</div></div><div style="text-align:right"><div class="hint" style="margin:0">' + ago(c.updatedAt) + '</div>' + unread + "</div></div>";
    }).join("");
    el.querySelectorAll(".conv").forEach(function (row) { row.addEventListener("click", function () { openConvo(row.getAttribute("data-id")); }); });
  }
  function openConvo(id) {
    currentConv = id;
    $("threadEmpty").classList.add("hidden");
    $("threadContent").classList.remove("hidden");
    document.querySelector(".inbox").classList.add("viewing");
    document.querySelectorAll("#convList .conv").forEach(function (r) { r.classList.toggle("active", r.getAttribute("data-id") === id); });
    loadThread(true);
    clearInterval(threadPoll); threadPoll = setInterval(function () { loadThread(false); }, 2500);
  }
  $("convBack").addEventListener("click", function () {
    currentConv = null;
    clearInterval(threadPoll); threadPoll = null;
    $("threadContent").classList.add("hidden");
    $("threadEmpty").classList.remove("hidden");
    document.querySelector(".inbox").classList.remove("viewing");
    document.querySelectorAll("#convList .conv").forEach(function (r) { r.classList.remove("active"); });
  });
  function loadThread(scroll) {
    if (!currentConv) return;
    api("/admin/conversations/" + currentConv).then(function (r) { return r.ok ? r.json() : null; }).then(function (d) {
      if (!d) return;
      var c = d.conversation;
      $("thName").textContent = c.name || "Visitor"; $("thEmail").textContent = c.email || "";
      updateToolbar(c);
      var body = $("thBody"); var atBottom = body.scrollHeight - body.scrollTop - body.clientHeight < 60;
      body.innerHTML = c.messages.map(renderMsg).join("");
      if (scroll || atBottom) body.scrollTop = body.scrollHeight;
    }).catch(function () {});
  }
  function renderMsg(m) {
    if (m.role === "system") return '<div class="sysm">' + esc(m.text) + "</div>";
    var lbl = m.role === "user" ? "" : m.role === "agent" ? '<div class="lbl">You</div>' : '<div class="lbl">AI</div>';
    var content = m.role === "assistant" ? md(m.text) : esc(m.text);
    return '<div class="m ' + m.role + '"><div>' + lbl + '<div class="bub">' + content + "</div></div></div>";
  }
  function updateToolbar(c) {
    var human = c.mode === "human", closed = c.status === "closed";
    $("mDot").className = "mdot " + (human ? "human" : "ai");
    $("mText").textContent = closed ? "Closed" : human ? "Live — you're replying" : "Automated (AI)";
    $("takeoverBtn").classList.toggle("hidden", human || closed);
    $("releaseBtn").classList.toggle("hidden", !human || closed);
    var box = $("replyBox"); box.disabled = closed; $("sendReply").disabled = closed || !box.value.trim();
    box.placeholder = closed ? "This conversation is closed." : human ? "Type your reply…" : "Type to reply (this takes over from the AI)…";
  }
  $("takeoverBtn").addEventListener("click", function () { setConvMode("human"); });
  $("releaseBtn").addEventListener("click", function () { setConvMode("ai"); });
  function setConvMode(mode) { api("/admin/conversations/" + currentConv + "/mode", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ mode: mode }) }).then(function () { toast(mode === "human" ? "You've taken over" : "Handed back to AI", "ok"); loadThread(true); }).catch(function () { toast("Failed", "err"); }); }
  $("closeBtn").addEventListener("click", function () { if (!confirm("Close this conversation?")) return; api("/admin/conversations/" + currentConv + "/close", { method: "POST" }).then(function () { toast("Conversation closed", "info"); $("convBack").click(); loadConvos(); }).catch(function () {}); });
  var replyBox = $("replyBox"), sendReply = $("sendReply");
  replyBox.addEventListener("input", function () { replyBox.style.height = "auto"; replyBox.style.height = Math.min(replyBox.scrollHeight, 110) + "px"; sendReply.disabled = !replyBox.value.trim(); });
  replyBox.addEventListener("keydown", function (e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); doReply(); } });
  sendReply.addEventListener("click", doReply);
  function doReply() { var text = replyBox.value.trim(); if (!text || !currentConv) return; sendReply.disabled = true; replyBox.value = ""; replyBox.style.height = "auto"; api("/admin/conversations/" + currentConv + "/reply", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: text }) }).then(function (r) { return r.json(); }).then(function () { loadThread(true); }).catch(function () { toast("Send failed", "err"); }); }
})();
