const qs = (id) => document.getElementById(id);

function setMsg(el, msg) {
  el.textContent = msg || "";
}

let logsCache = [];

async function api(path, { method = "GET", token = null, body = null } = {}) {
  const headers = {};
  if (token) headers["Authorization"] = `Bearer ${token}`;
  if (body !== null) headers["Content-Type"] = "application/json";

  const res = await fetch(path, {
    method,
    headers,
    body: body === null ? undefined : JSON.stringify(body),
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) {
    const err = data?.error?.message || `HTTP ${res.status}`;
    const code = data?.error?.code || "error";
    const e = new Error(err);
    e.code = code;
    e.status = res.status;
    throw e;
  }
  return data;
}

function getToken() {
  return localStorage.getItem("admin_token");
}

function setToken(token) {
  if (token) localStorage.setItem("admin_token", token);
  else localStorage.removeItem("admin_token");
}

function formatUnixTs(ts) {
  const d = new Date(Number(ts) * 1000);
  if (!Number.isFinite(d.getTime())) return String(ts || "");
  return d.toLocaleString(undefined, {
    year: "2-digit",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  });
}

function formatAge(ts) {
  const seconds = Math.max(0, Math.floor(Date.now() / 1000 - Number(ts)));
  if (seconds < 60) return `${seconds}s`;
  if (seconds < 60 * 60) return `${Math.floor(seconds / 60)}m`;
  if (seconds < 60 * 60 * 24) return `${Math.floor(seconds / 3600)}h`;
  return `${Math.floor(seconds / 86400)}d`;
}

function shortId(value) {
  const s = String(value || "");
  if (s.length <= 18) return s;
  return `${s.slice(0, 8)}…${s.slice(-6)}`;
}

function levelClass(level) {
  const v = String(level || "").toLowerCase();
  if (v === "error") return "badge error";
  if (v === "warn" || v === "warning") return "badge warn";
  return "badge info";
}

function formatDetailValue(value) {
  if (value === null || value === undefined) return "";
  if (typeof value === "string") return value.length > 48 ? shortId(value) : value;
  if (typeof value === "number" || typeof value === "boolean") return String(value);
  try {
    const s = JSON.stringify(value);
    if (s.length <= 80) return s;
    return `${s.slice(0, 77)}…`;
  } catch {
    return String(value);
  }
}

function summarizeDetails(details) {
  if (!details || typeof details !== "object") return "";
  const entries = Object.entries(details).filter(([, v]) => v !== null && v !== undefined);
  if (entries.length === 0) return "";

  const preferredKeys = [
    "user_id",
    "admin_id",
    "conversation_id",
    "message_id",
    "integration_id",
    "bot_user_id",
    "target_conversation_id",
    "upload_id",
    "attachment_id",
  ];
  const preferredKeySet = new Set(preferredKeys);
  const byKey = new Map(entries);
  const ordered = [];
  for (const k of preferredKeys) {
    if (byKey.has(k)) ordered.push([k, byKey.get(k)]);
  }
  ordered.push(...entries.filter(([k]) => !preferredKeySet.has(k)).sort((a, b) => a[0].localeCompare(b[0])));

  const parts = [];
  for (const [k, v] of ordered) {
    const vs = formatDetailValue(v);
    parts.push(`${k}=${vs}`);
    if (parts.length >= 3) break;
  }
  return parts.join(", ");
}

function renderLogs() {
  const table = qs("logsTable");
  if (!table) return;
  const tbody = table.querySelector("tbody");
  if (!tbody) return;

  const q = String(qs("logsSearch")?.value || "")
    .trim()
    .toLowerCase();
  const level = String(qs("logsLevel")?.value || "")
    .trim()
    .toUpperCase();

  const filtered = (logsCache || []).filter((l) => {
    if (level && String(l.level || "").toUpperCase() !== level) return false;
    if (!q) return true;
    const hay = `${l.event || ""} ${l.level || ""} ${l.id || ""} ${JSON.stringify(l.details || {})}`.toLowerCase();
    return hay.includes(q);
  });

  tbody.innerHTML = "";
  if (filtered.length === 0) {
    const tr = document.createElement("tr");
    const td = document.createElement("td");
    td.colSpan = 5;
    td.className = "muted";
    td.textContent = "No logs";
    tr.appendChild(td);
    tbody.appendChild(tr);
    return;
  }

  const frag = document.createDocumentFragment();
  for (const l of filtered) {
    const tr = document.createElement("tr");

    const timeTd = document.createElement("td");
    timeTd.className = "nowrap";
    const tsText = formatUnixTs(l.created_at);
    const mono = document.createElement("div");
    mono.className = "mono";
    mono.title = new Date(Number(l.created_at) * 1000).toLocaleString();
    mono.textContent = tsText;
    const age = document.createElement("div");
    age.className = "muted";
    age.textContent = `${formatAge(l.created_at)} ago`;
    timeTd.appendChild(mono);
    timeTd.appendChild(age);

    const levelTd = document.createElement("td");
    levelTd.className = "nowrap";
    const levelSpan = document.createElement("span");
    levelSpan.className = levelClass(l.level);
    levelSpan.textContent = String(l.level || "INFO");
    levelTd.appendChild(levelSpan);

    const eventTd = document.createElement("td");
    const eventCode = document.createElement("code");
    eventCode.textContent = String(l.event || "");
    eventTd.appendChild(eventCode);

    const detailsTd = document.createElement("td");
    const summary = summarizeDetails(l.details);
    if (l.details && typeof l.details === "object") {
      const det = document.createElement("details");
      det.className = "logDetails";
      const sum = document.createElement("summary");
      sum.textContent = summary || "details";
      det.appendChild(sum);
      const pre = document.createElement("pre");
      pre.textContent = JSON.stringify(l.details, null, 2);
      det.appendChild(pre);
      detailsTd.appendChild(det);
    } else {
      detailsTd.textContent = summary || "";
    }

    const idTd = document.createElement("td");
    idTd.className = "nowrap";
    const id = String(l.id || "");
    const code = document.createElement("code");
    code.textContent = shortId(id);
    code.title = id;
    idTd.appendChild(code);

    tr.appendChild(timeTd);
    tr.appendChild(levelTd);
    tr.appendChild(eventTd);
    tr.appendChild(detailsTd);
    tr.appendChild(idTd);
    frag.appendChild(tr);
  }
  tbody.appendChild(frag);
}

async function refresh() {
  const token = getToken();
  if (!token) return;
  qs("logoutBtn").classList.remove("hidden");
  qs("appSection").classList.remove("hidden");

  const limitValue = qs("logsLimit")?.value || "120";
  let limit = Number.parseInt(limitValue, 10);
  if (!Number.isFinite(limit)) limit = 120;
  limit = Math.max(1, Math.min(500, limit));

  const [metrics, users, groups, logs] = await Promise.all([
    api("/api/v1/admin/metrics", { token }),
    api("/api/v1/admin/users", { token }),
    api("/api/v1/admin/groups", { token }),
    api(`/api/v1/admin/logs?limit=${encodeURIComponent(String(limit))}`, { token }),
  ]);

  qs("metricsBox").textContent = JSON.stringify(metrics, null, 2);
  qs("groupsBox").textContent = JSON.stringify(groups, null, 2);
  logsCache = logs?.logs || [];
  renderLogs();

  const tbody = qs("usersTable").querySelector("tbody");
  tbody.innerHTML = "";
  for (const u of users.users) {
    const tr = document.createElement("tr");
    tr.innerHTML = `
      <td><code>${u.id}</code></td>
      <td>${u.email}</td>
      <td>${u.username}</td>
      <td>${u.is_admin ? "yes" : ""}</td>
      <td>${u.is_bot ? (u.bot_verified ? "verified" : "bot") : ""}</td>
      <td>${u.is_banned ? "yes" : ""}</td>
      <td class="actions"></td>
    `;
    const actions = tr.querySelector(".actions");

    const banBtn = document.createElement("button");
    banBtn.textContent = u.is_banned ? "Unban" : "Ban";
    banBtn.className = "secondary";
    banBtn.onclick = async () => {
      const banned = !u.is_banned;
      const reason = banned ? prompt("Ban reason (optional):") : null;
      await api(`/api/v1/admin/users/${u.id}/ban`, { method: "POST", token, body: { banned, reason } });
      await refresh();
    };
    actions.appendChild(banBtn);

    const warnBtn = document.createElement("button");
    warnBtn.textContent = "Warn";
    warnBtn.className = "secondary";
    warnBtn.onclick = async () => {
      const reason = prompt("Warning reason:") || "";
      await api(`/api/v1/admin/users/${u.id}/warn`, { method: "POST", token, body: { reason } });
      await refresh();
    };
    actions.appendChild(warnBtn);

    const otpBtn = document.createElement("button");
    otpBtn.textContent = "OTP reset";
    otpBtn.className = "secondary";
    otpBtn.onclick = async () => {
      const res = await api(`/api/v1/admin/users/${u.id}/otp-reset`, { method: "POST", token, body: {} });
      alert(`OTP: ${res.otp}\nExpires at (unix ts): ${res.expires_at}`);
      await refresh();
    };
    actions.appendChild(otpBtn);

    tbody.appendChild(tr);
  }
}

qs("bootstrapBtn").onclick = async () => {
  setMsg(qs("bootstrapMsg"), "");
  try {
    await api("/api/v1/admin/bootstrap", {
      method: "POST",
      body: {
        email: qs("bootstrapEmail").value,
        username: qs("bootstrapUsername").value,
        password: qs("bootstrapPassword").value,
      },
    });
    setMsg(qs("bootstrapMsg"), "Admin created. Please login.");
  } catch (e) {
    if (e.code === "bootstrap_closed") {
      setMsg(qs("bootstrapMsg"), "Bootstrap already closed (admin exists).");
    } else {
      setMsg(qs("bootstrapMsg"), `${e.message} (${e.code || "error"})`);
    }
  }
};

qs("loginBtn").onclick = async () => {
  setMsg(qs("loginMsg"), "");
  try {
    const res = await api("/api/v1/auth/login", {
      method: "POST",
      body: { login: qs("loginValue").value, password: qs("loginPassword").value },
    });
    setToken(res.token);
    qs("loginSection").classList.add("hidden");
    qs("bootstrapSection").classList.add("hidden");
    await refresh();
  } catch (e) {
    setMsg(qs("loginMsg"), `${e.message} (${e.code || "error"})`);
  }
};

qs("logoutBtn").onclick = async () => {
  const token = getToken();
  try {
    if (token) await api("/api/v1/auth/logout", { method: "POST", token });
  } finally {
    setToken(null);
    location.reload();
  }
};

// Auto-start
(async () => {
  const token = getToken();
  if (token) {
    qs("loginSection").classList.add("hidden");
    qs("bootstrapSection").classList.add("hidden");
    try {
      await refresh();
    } catch {
      setToken(null);
      location.reload();
    }
  }
})();

// Logs controls
qs("logsRefreshBtn")?.addEventListener("click", async () => {
  try {
    await refresh();
  } catch {
    // ignore
  }
});
qs("logsSearch")?.addEventListener("input", () => renderLogs());
qs("logsLevel")?.addEventListener("change", () => renderLogs());
