/* RAPPORT Hosting — Frontend-Logik (Vanilla JS).
 *
 * Reine Client-Seite: spricht ausschließlich mit dem proprietären Backend
 * unter /api (RAPPORT-HOST). Hier liegt KEINE Geschäftslogik, nur fetch +
 * Rendering — so bleibt RAPPORT-WEBSITE sauber AGPL/öffentlich.
 *
 * Token im localStorage; gerendert wird in #hosting-root je nach data-page.
 */
(function () {
  "use strict";
  const root = document.getElementById("hosting-root");
  if (!root) return;
  const page = root.dataset.page || "login";

  const TOKEN_KEY = "rapport_host_token";
  const tok = {
    get: () => localStorage.getItem(TOKEN_KEY),
    set: (t) => localStorage.setItem(TOKEN_KEY, t),
    clear: () => localStorage.removeItem(TOKEN_KEY),
    get isLoggedIn() { return !!localStorage.getItem(TOKEN_KEY); },
  };

  async function api(method, path, body) {
    const headers = { "Content-Type": "application/json" };
    const t = tok.get();
    if (t) headers.Authorization = "Bearer " + t;
    const res = await fetch("/api" + path, {
      method, headers, body: body ? JSON.stringify(body) : undefined,
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error(data.error || ("Fehler " + res.status));
    return data;
  }

  const go = (p) => { window.location.href = p; };
  const esc = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) =>
    ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[c]));

  function card(inner, wide) {
    return '<div class="hosting-card' + (wide ? " wide" : "") + '">' + inner + "</div>";
  }

  // Auth-Karten als 2-Spalter: links Formular, rechts Vertrauens-Panel.
  // (Login/Register) — wirkt deutlich hochwertiger als die nackte Box.
  function authCard(formInner) {
    return (
      '<div class="hosting-auth">' +
        '<div class="hosting-auth-form">' + formInner + "</div>" +
        '<div class="hosting-auth-aside">' +
          '<div class="rapport-logo-card" style="margin:0 0 28px"><div class="rapport-logo-text">RAPPORT</div><div class="rapport-logo-sub">Hosting</div></div>' +
          '<ul class="hosting-aside-list">' +
            "<li>🇨🇭 Daten in der Schweiz</li>" +
            "<li>Tägliche Backups</li>" +
            "<li>In Minuten startklar</li>" +
            "<li>Monatlich kündbar</li>" +
          "</ul>" +
        "</div>" +
      "</div>"
    );
  }
  function msg(el, text, kind) {
    el.innerHTML = text ? '<div class="hosting-msg ' + kind + '">' + esc(text) + "</div>" : "";
  }

  // ── Login ──────────────────────────────────────────────────────────────
  function renderLogin() {
    // Schon eingeloggt? Dann nicht das Login-Formular zeigen, sondern direkt
    // ins Konto — der häufigste Grund für "ich muss mich ständig neu anmelden".
    if (tok.isLoggedIn) return go("/konto/");
    root.innerHTML = card(authCard(
      '<div class="hosting-title">Anmelden</div>' +
      '<div class="hosting-sub">Zu Ihrer Rapport-Instanz</div>' +
      '<div id="m"></div>' +
      '<form id="f">' +
      '<label class="hosting-label">E-Mail</label>' +
      '<input class="hosting-input" type="email" id="email" placeholder="name@studio.ch" autofocus>' +
      '<label class="hosting-label">Passwort</label>' +
      '<input class="hosting-input" type="password" id="pw" placeholder="••••••">' +
      '<button class="hosting-btn hosting-btn-primary" id="sub">Anmelden</button>' +
      "</form>" +
      '<div class="hosting-foot">Noch kein Konto? ' +
      '<button class="hosting-link" id="toReg">Registrieren</button></div>'
    ), true);
    const m = root.querySelector("#m");
    root.querySelector("#toReg").onclick = () => go("/register/");
    root.querySelector("#f").onsubmit = async (e) => {
      e.preventDefault();
      const sub = root.querySelector("#sub"); sub.disabled = true; msg(m, "", "");
      try {
        const { token } = await api("POST", "/auth/login", {
          email: root.querySelector("#email").value.trim(),
          password: root.querySelector("#pw").value,
        });
        tok.set(token); go("/konto/");
      } catch (err) { msg(m, err.message, "err"); sub.disabled = false; }
    };
  }

  // ── Registrierung ──────────────────────────────────────────────────────
  function renderRegister() {
    if (tok.isLoggedIn) return go("/konto/");
    root.innerHTML = card(authCard(
      '<div class="hosting-title">Konto erstellen</div>' +
      '<div class="hosting-sub">In Minuten zur eigenen Instanz</div>' +
      '<div id="m"></div>' +
      '<form id="f">' +
      '<label class="hosting-label">E-Mail</label>' +
      '<input class="hosting-input" type="email" id="email" placeholder="name@studio.ch" autofocus>' +
      '<label class="hosting-label">Passwort</label>' +
      '<input class="hosting-input" type="password" id="pw" placeholder="min. 8 Zeichen">' +
      '<button class="hosting-btn hosting-btn-primary" id="sub">Konto erstellen</button>' +
      "</form>" +
      '<div class="hosting-foot">Schon ein Konto? ' +
      '<button class="hosting-link" id="toLogin">Anmelden</button></div>'
    ), true);
    const m = root.querySelector("#m");
    root.querySelector("#toLogin").onclick = () => go("/login/");
    root.querySelector("#f").onsubmit = async (e) => {
      e.preventDefault();
      const sub = root.querySelector("#sub"); sub.disabled = true; msg(m, "", "");
      try {
        const { token } = await api("POST", "/auth/register", {
          email: root.querySelector("#email").value.trim(),
          password: root.querySelector("#pw").value,
        });
        tok.set(token); go("/konto/");
      } catch (err) { msg(m, err.message, "err"); sub.disabled = false; }
    };
  }

  // ── Konto / Dashboard (Tabs: Übersicht · Profil · Sicherheit) ───────────
  let acctData = null;       // gecachte /account/me-Antwort
  let acctTab = "overview";

  async function renderKonto() {
    if (!tok.isLoggedIn) return go("/login/");
    root.innerHTML = card('<div class="hosting-sub">Lädt…</div>', true);
    try { acctData = await api("GET", "/account/me"); }
    catch (err) {
      if (/angemeldet|abgelaufen|ungültig/i.test(err.message)) { tok.clear(); return go("/login/"); }
      root.innerHTML = card('<div class="hosting-msg err">' + esc(err.message) + "</div>"); return;
    }
    paintKonto();
  }

  function paintKonto() {
    const { account } = acctData;
    const tabs = [["overview", "Übersicht"], ["profile", "Profil"], ["security", "Sicherheit"]];
    const head =
      '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">' +
      '<div class="hosting-title" style="text-align:left;margin:0">Mein Konto</div>' +
      '<button class="hosting-link" id="logout">Abmelden</button></div>' +
      '<div class="hosting-sub" style="text-align:left;margin-bottom:20px">' + esc(account.email) + "</div>" +
      '<div class="hosting-tabs">' +
      tabs.map(([id, label]) =>
        '<button class="hosting-tab' + (acctTab === id ? " active" : "") + '" data-tab="' + id + '">' + label + "</button>"
      ).join("") + "</div>";

    const body = { overview: tabOverview, profile: tabProfile, security: tabSecurity }[acctTab]();
    root.innerHTML = card(head + '<div id="tabbody">' + body + "</div>", true);

    root.querySelector("#logout").onclick = () => { tok.clear(); go("/"); };
    root.querySelectorAll("[data-tab]").forEach((b) =>
      (b.onclick = () => { acctTab = b.dataset.tab; paintKonto(); })
    );
    wireTab();
  }

  // — Tab: Übersicht (Abo + Instanzen) —
  function tabOverview() {
    const { subscription, instances, plans } = acctData;
    const params = new URLSearchParams(location.search);
    let h = "";
    if (params.get("provisioned") === "1")
      h += '<div class="hosting-msg ok">Zahlung erfolgreich — Ihre Instanz wird bereitgestellt.</div>';

    if (subscription) {
      const pastDue = subscription.status === "past_due";
      if (pastDue) h += '<div class="hosting-msg err">Letzte Zahlung fehlgeschlagen — bitte Zahlungsmittel im Abo-Portal aktualisieren.</div>';
      h += '<div class="hosting-row"><span class="muted">Abo</span><b>' +
        esc(subscription.plan) + " · " + esc(subscription.status) + "</b></div>";
      if (subscription.current_period_end)
        h += '<div class="hosting-row"><span class="muted">Nächste Verlängerung</span><span>' +
          esc(new Date(subscription.current_period_end).toLocaleDateString("de-CH")) + "</span></div>";
      h += '<div style="margin-top:14px"><button class="hosting-btn hosting-btn-dark" id="managePlan" style="width:auto;padding:9px 18px">Abo verwalten</button></div>';
    }

    if (instances && instances.length) {
      h += '<div style="margin:22px 0 10px;font-weight:600;font-size:14px">Ihre Instanzen</div>';
      h += instances.map((i) =>
        '<div class="hosting-row"><div><b>' + esc(i.label || i.studio_slug) + "</b>" +
        '<div class="muted" style="font-size:12px">' + esc(i.instance_url) + "</div></div>" +
        '<a class="hosting-btn hosting-btn-primary" style="width:auto;padding:8px 16px;text-decoration:none" href="' +
        esc(i.instance_url) + '" target="_blank" rel="noreferrer">Öffnen →</a></div>'
      ).join("");
      // Weitere Instanz (Multi-Instanz vorbereitet — Backend-Sperre öffnen wir später)
      h += '<div style="margin-top:16px"><button class="hosting-btn hosting-btn-dark" id="addInstance">+ Weitere Instanz</button></div>';
    } else {
      h += '<div style="margin:18px 0 8px;font-size:14px;color:var(--rapport-text-2)">Wählen Sie ein Abo, um Ihre Instanz freizuschalten:</div>' +
        '<div class="hosting-plans">' + (plans || []).map(planCard).join("") + "</div>";
    }
    return h;
  }

  // — Tab: Profil (Firma / Rechnungsadresse) —
  function tabProfile() {
    const a = acctData.account;
    const f = (id, label, val, ph) =>
      '<label class="hosting-label">' + label + "</label>" +
      '<input class="hosting-input" id="' + id + '" value="' + esc(val || "") + '" placeholder="' + (ph || "") + '">';
    return '<div id="pmsg"></div>' +
      f("company", "Firma / Büro", a.company, "Architektur Muster GmbH") +
      f("contact_name", "Ansprechperson", a.contact_name, "Vor- und Nachname") +
      f("street", "Strasse & Nr.", a.street) +
      '<div style="display:flex;gap:12px">' +
      '<div style="flex:0 0 110px">' + f("zip", "PLZ", a.zip) + "</div>" +
      '<div style="flex:1">' + f("city", "Ort", a.city) + "</div></div>" +
      f("country", "Land", a.country || "CH") +
      f("phone", "Telefon", a.phone) +
      '<button class="hosting-btn hosting-btn-primary" id="saveProfile" style="margin-top:8px">Speichern</button>';
  }

  // — Tab: Sicherheit (Passwort) —
  function tabSecurity() {
    return '<div id="smsg"></div>' +
      '<label class="hosting-label">Aktuelles Passwort</label>' +
      '<input class="hosting-input" type="password" id="curPw">' +
      '<label class="hosting-label">Neues Passwort</label>' +
      '<input class="hosting-input" type="password" id="newPw" placeholder="min. 8 Zeichen">' +
      '<button class="hosting-btn hosting-btn-primary" id="savePw" style="margin-top:8px">Passwort ändern</button>';
  }

  // — Event-Wiring je Tab —
  function wireTab() {
    if (acctTab === "overview") {
      root.querySelectorAll("[data-plan]").forEach((b) =>
        (b.onclick = async () => {
          b.disabled = true;
          try { const { url } = await api("POST", "/billing/checkout", { planId: b.dataset.plan }); go(url); }
          catch (err) { alert(err.message); b.disabled = false; }
        })
      );
      const add = root.querySelector("#addInstance");
      if (add) add.onclick = () => alert("Weitere Instanzen kommen bald. Kontaktieren Sie uns für ein Mehrfach-Abo.");
      const manage = root.querySelector("#managePlan");
      if (manage) manage.onclick = async () => {
        manage.disabled = true;
        try { const { url } = await api("POST", "/billing/portal"); go(url); }
        catch (err) { alert(err.message); manage.disabled = false; }
      };
    }
    if (acctTab === "profile") {
      root.querySelector("#saveProfile").onclick = async (e) => {
        const btn = e.target; btn.disabled = true;
        const m = root.querySelector("#pmsg");
        const payload = {};
        ["company", "contact_name", "street", "zip", "city", "country", "phone"].forEach(
          (id) => (payload[id] = root.querySelector("#" + id).value.trim())
        );
        try {
          const { account } = await api("PATCH", "/account/me", payload);
          acctData.account = { ...acctData.account, ...account };
          msg(m, "Gespeichert.", "ok");
        } catch (err) { msg(m, err.message, "err"); }
        btn.disabled = false;
      };
    }
    if (acctTab === "security") {
      root.querySelector("#savePw").onclick = async (e) => {
        const btn = e.target; btn.disabled = true;
        const m = root.querySelector("#smsg");
        try {
          await api("POST", "/account/password", {
            currentPassword: root.querySelector("#curPw").value,
            newPassword: root.querySelector("#newPw").value,
          });
          root.querySelector("#curPw").value = ""; root.querySelector("#newPw").value = "";
          msg(m, "Passwort geändert.", "ok");
        } catch (err) { msg(m, err.message, "err"); }
        btn.disabled = false;
      };
    }
  }

  function planCard(p) {
    return '<div class="hosting-plan' + (p.recommended ? " rec" : "") + '">' +
      (p.recommended ? '<div class="pbadge">Empfohlen</div>' : "") +
      '<div class="pname">' + esc(p.name) + "</div>" +
      '<div class="pprice">CHF ' + esc(p.priceChf) + '<span style="font-size:13px;color:var(--rapport-text-3)">/' + esc(p.interval) + "</span></div>" +
      "<ul>" + (p.features || []).map((f) => "<li>" + esc(f) + "</li>").join("") + "</ul>" +
      '<button class="hosting-btn hosting-btn-primary" data-plan="' + esc(p.id) + '">Wählen</button></div>';
  }

  // ── Preise (öffentlich, mit CTA in den Flow) ───────────────────────────
  async function renderPreise() {
    root.innerHTML = card('<div class="hosting-sub">Lädt…</div>', true);
    let plans = [];
    try { plans = (await api("GET", "/billing/plans")).plans; } catch (_) {}
    const html =
      '<div class="hosting-title">Abo wählen</div>' +
      '<div class="hosting-sub">Monatlich kündbar · Preise in CHF, exkl. MwSt.</div>' +
      '<div class="hosting-plans">' + plans.map(planCard).join("") + "</div>";
    root.innerHTML = card(html, true);
    root.querySelectorAll("[data-plan]").forEach((b) => {
      b.onclick = () => go(tok.isLoggedIn ? "/konto/" : "/register/");
    });
  }

  // ── Admin / Betreiber-Bereich (SEPARATES Login, eigener Token) ────────────
  const ADMIN_KEY = "rapport_admin_token";
  const adminTok = {
    get: () => localStorage.getItem(ADMIN_KEY),
    set: (t) => localStorage.setItem(ADMIN_KEY, t),
    clear: () => localStorage.removeItem(ADMIN_KEY),
  };
  // wie api(), aber mit Admin-Token statt Kunden-Token.
  async function adminApi(method, path, body) {
    const headers = { "Content-Type": "application/json" };
    const t = adminTok.get();
    if (t) headers.Authorization = `Bearer ${t}`;
    const res = await fetch(`/api${path}`, { method, headers, body: body ? JSON.stringify(body) : undefined });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) { const e = new Error(data.error || `Fehler ${res.status}`); e.status = res.status; throw e; }
    return data;
  }

  function renderAdminLogin(errText) {
    root.innerHTML = card(
      '<div class="hosting-title">Betreiber-Login</div>' +
      '<div class="hosting-sub">Interner Bereich</div>' +
      (errText ? '<div class="hosting-msg err">' + esc(errText) + "</div>" : "") +
      '<form id="af"><label class="hosting-label">Admin-Passwort</label>' +
      '<input class="hosting-input" type="password" id="apw" autofocus>' +
      '<button class="hosting-btn hosting-btn-primary" id="asub">Anmelden</button></form>'
    );
    root.querySelector("#af").onsubmit = async (e) => {
      e.preventDefault();
      const sub = root.querySelector("#asub"); sub.disabled = true;
      try {
        const { token } = await adminApi("POST", "/admin/login", { password: root.querySelector("#apw").value });
        adminTok.set(token); renderAdmin();
      } catch (err) { renderAdminLogin(err.message); }
    };
  }

  async function renderAdmin() {
    if (!adminTok.get()) return renderAdminLogin("");
    root.innerHTML = card('<div class="hosting-sub">Lädt…</div>', true);
    let stats, accounts;
    try {
      [stats, accounts] = await Promise.all([
        adminApi("GET", "/admin/stats"),
        adminApi("GET", "/admin/accounts"),
      ]);
    } catch (err) {
      if (err.status === 401 || err.status === 403) { adminTok.clear(); return renderAdminLogin("Bitte neu anmelden."); }
      root.innerHTML = card('<div class="hosting-msg err">' + esc(err.message) + "</div>");
      return;
    }

    adminCache = { stats, accounts: accounts.accounts };
    paintAdmin();
  }

  // Such-/Filter-State des Cockpits.
  let adminCache = null;
  let adminSearch = "";
  let adminPlanFilter = "";

  function statCard(label, val, sub) {
    return '<div class="admin-stat"><div class="admin-stat-num">' + esc(val) + "</div>" +
      '<div class="admin-stat-label">' + esc(label) + "</div>" +
      (sub ? '<div class="admin-stat-sub">' + esc(sub) + "</div>" : "") + "</div>";
  }

  function paintAdmin() {
    const { stats } = adminCache;
    const planNames = Object.values(stats.byPlan || {});
    const planChips = planNames.length
      ? '<div class="admin-planbar">' + planNames.map((p) =>
          '<div class="admin-planchip"><b>' + esc(p.name) + "</b> · " + esc(p.count) +
          ' <span class="muted">(CHF ' + esc(p.revenue) + ")</span></div>"
        ).join("") + "</div>"
      : "";

    // Kunden filtern (Suche über Email/Firma + Plan-Filter).
    const q = adminSearch.trim().toLowerCase();
    const list = adminCache.accounts.filter((a) => {
      const matchesQ = !q || (a.email + " " + (a.company || "")).toLowerCase().includes(q);
      const matchesP = !adminPlanFilter || a.plan === adminPlanFilter;
      return matchesQ && matchesP;
    });

    const rows = list.map((a) =>
      '<tr class="admin-row" data-id="' + esc(a.id) + '">' +
      "<td><b>" + esc(a.email) + "</b>" +
        (a.company ? '<div class="muted" style="font-size:12px">' + esc(a.company) + "</div>" : "") + "</td>" +
      "<td>" + (a.plan ? '<span class="admin-badge">' + esc(a.plan) + "</span>" +
        (a.sub_status && a.sub_status !== "active"
          ? ' <span class="admin-badge ' + (a.sub_status === "past_due" ? "warn" : "") + '" style="font-size:10px">' + esc(a.sub_status) + "</span>"
          : "")
        : '<span class="muted">—</span>') + "</td>" +
      '<td style="text-align:center">' + esc(a.instance_count) + "</td>" +
      '<td class="muted" style="font-size:12px">' + esc(new Date(a.created_at).toLocaleDateString("de-CH")) + "</td>" +
      '<td style="text-align:right"><span class="admin-chevron">›</span></td>' +
      "</tr>"
    ).join("");

    const planOptions = ['<option value="">Alle Pläne</option>']
      .concat(planNames.map((p) => '<option value="' + esc(p.name.toLowerCase()) + '"' +
        (adminPlanFilter === p.name.toLowerCase() ? " selected" : "") + ">" + esc(p.name) + "</option>"))
      .join("");

    const html =
      '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px">' +
      '<div class="hosting-title" style="text-align:left;margin:0">Cockpit</div>' +
      '<div style="display:flex;gap:14px;align-items:center">' +
      '<button class="hosting-link" id="ahealth">Health-Check</button>' +
      '<button class="hosting-link" id="aexport">CSV-Export</button>' +
      '<button class="hosting-link" id="alogout">Abmelden</button></div></div>' +
      (stats.pastDueSubscriptions
        ? '<div class="hosting-msg err">⚠ ' + esc(stats.pastDueSubscriptions) +
          " Abo(s) mit fehlgeschlagener Zahlung (past_due) — Kunden kontaktieren.</div>"
        : "") +
      '<div id="healthbar"></div>' +
      '<div class="admin-stats">' +
        statCard("Kunden", stats.accounts, "+" + (stats.newAccounts30d || 0) + " (30 T.)") +
        statCard("Aktive Abos", stats.activeSubscriptions) +
        statCard("Instanzen", stats.activeInstances + "/" + stats.instances,
          (stats.suspendedInstances ? stats.suspendedInstances + " gesperrt" : "")) +
        statCard("MRR", "CHF " + stats.mrrChf, "ARR CHF " + (stats.arrChf || stats.mrrChf * 12)) +
      "</div>" +
      planChips +
      '<div class="admin-toolbar">' +
        '<input class="hosting-input admin-search" id="asearch" placeholder="Suche E-Mail / Firma…" value="' + esc(adminSearch) + '">' +
        '<select class="hosting-input admin-filter" id="afilter">' + planOptions + "</select>" +
      "</div>" +
      '<table class="admin-table"><thead><tr><th>Konto</th><th>Abo</th><th>Inst.</th><th>Seit</th><th></th></tr></thead>' +
      "<tbody>" + (rows || '<tr><td colspan="5" class="muted">Keine Treffer.</td></tr>') + "</tbody></table>";

    root.innerHTML = card(html, true);
    root.querySelector("#alogout").onclick = () => { adminTok.clear(); renderAdminLogin(""); };
    root.querySelector("#aexport").onclick = async () => {
      // CSV braucht den Admin-Token im Header → per fetch holen + Blob-Download.
      try {
        const res = await fetch("/api/admin/export/accounts.csv", {
          headers: { Authorization: "Bearer " + adminTok.get() },
        });
        if (!res.ok) throw new Error("Export fehlgeschlagen (" + res.status + ")");
        const blob = await res.blob();
        const a = document.createElement("a");
        a.href = URL.createObjectURL(blob);
        a.download = "rapport-kunden.csv";
        document.body.appendChild(a); a.click(); a.remove();
        URL.revokeObjectURL(a.href);
      } catch (err) { alert(err.message); }
    };
    root.querySelector("#ahealth").onclick = async () => {
      const bar = root.querySelector("#healthbar");
      bar.innerHTML = '<div class="hosting-msg">Prüfe Instanzen…</div>';
      try {
        const h = await adminApi("GET", "/admin/health");
        if (h.mock) {
          bar.innerHTML = '<div class="hosting-msg">Health-Check im Mock-Modus nicht aussagekräftig ' +
            "(keine echten Instanzen). " + esc(h.instances.length) + " aktive Instanz(en).</div>";
        } else if (h.down > 0) {
          bar.innerHTML = '<div class="hosting-msg err">⚠ ' + esc(h.down) + " von " + esc(h.checked) +
            " Instanzen nicht erreichbar (down).</div>";
        } else {
          bar.innerHTML = '<div class="hosting-msg ok">Alle ' + esc(h.checked) + " Instanzen erreichbar.</div>";
        }
      } catch (err) { bar.innerHTML = '<div class="hosting-msg err">' + esc(err.message) + "</div>"; }
    };
    const s = root.querySelector("#asearch");
    s.oninput = () => { adminSearch = s.value; const pos = s.selectionStart; paintAdmin(); const n = root.querySelector("#asearch"); n.focus(); n.setSelectionRange(pos, pos); };
    root.querySelector("#afilter").onchange = (e) => { adminPlanFilter = e.target.value; paintAdmin(); };
    root.querySelectorAll(".admin-row").forEach((r) =>
      (r.onclick = () => renderAdminDetail(r.dataset.id))
    );
  }

  // — Kunden-Detailansicht (Profil, Abo-Historie, Instanzen + Aktionen) —
  async function renderAdminDetail(id) {
    root.innerHTML = card('<div class="hosting-sub">Lädt…</div>', true);
    let d;
    try { d = await adminApi("GET", "/admin/accounts/" + id); }
    catch (err) {
      if (err.status === 401 || err.status === 403) { adminTok.clear(); return renderAdminLogin("Bitte neu anmelden."); }
      root.innerHTML = card('<div class="hosting-msg err">' + esc(err.message) + "</div>"); return;
    }
    const { account: a, subscriptions, instances } = d;

    const profile = [
      ["Firma", a.company], ["Ansprechperson", a.contact_name],
      ["Adresse", [a.street, [a.zip, a.city].filter(Boolean).join(" "), a.country].filter(Boolean).join(", ")],
      ["Telefon", a.phone],
    ].filter(([, v]) => v).map(([k, v]) =>
      '<div class="hosting-row"><span class="muted">' + esc(k) + "</span><span>" + esc(v) + "</span></div>"
    ).join("") || '<div class="muted" style="padding:8px 0">Keine Profildaten.</div>';

    const subRows = subscriptions.length ? subscriptions.map((s) =>
      '<div class="hosting-row"><span><span class="admin-badge">' + esc(s.plan) + "</span> " + esc(s.status) +
      (s.priceChf != null ? ' <span class="muted">CHF ' + esc(s.priceChf) + "</span>" : "") + "</span>" +
      '<span class="muted" style="font-size:12px">' + esc(new Date(s.created_at).toLocaleDateString("de-CH")) + "</span></div>"
    ).join("") : '<div class="muted" style="padding:8px 0">Kein Abo.</div>';

    const instRows = instances.length ? instances.map((i) =>
      '<div class="hosting-row"><div><b>' + esc(i.label || i.studio_slug) + "</b> " +
      '<span class="admin-badge ' + (i.status === "active" ? "ok" : "warn") + '">' + esc(i.status) + "</span>" +
      '<div class="muted" style="font-size:12px">' + esc(i.instance_url) + "</div></div>" +
      '<div style="display:flex;gap:8px">' +
        '<a class="hosting-btn admin-mini" href="' + esc(i.instance_url) + '" target="_blank" rel="noreferrer">Öffnen</a>' +
        (i.status === "active"
          ? '<button class="hosting-btn admin-mini warn" data-act="suspend" data-iid="' + esc(i.id) + '">Sperren</button>'
          : '<button class="hosting-btn admin-mini ok" data-act="reactivate" data-iid="' + esc(i.id) + '">Reaktivieren</button>') +
      "</div></div>"
    ).join("") : '<div class="muted" style="padding:8px 0">Keine Instanzen.</div>';

    const html =
      '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">' +
      '<button class="hosting-link" id="aback">‹ Zurück</button>' +
      '<button class="hosting-link" id="alogout">Abmelden</button></div>' +
      '<div class="hosting-title" style="text-align:left;margin:0 0 2px">' + esc(a.email) + "</div>" +
      '<div class="hosting-sub" style="text-align:left;margin-bottom:22px">Kunde seit ' +
        esc(new Date(a.created_at).toLocaleDateString("de-CH")) + "</div>" +
      '<div class="admin-section">Profil</div>' + profile +
      '<div class="admin-section">Abo-Historie</div>' + subRows +
      '<div class="admin-section">Instanzen</div>' + instRows;

    root.innerHTML = card(html, true);
    root.querySelector("#aback").onclick = () => paintAdmin();
    root.querySelector("#alogout").onclick = () => { adminTok.clear(); renderAdminLogin(""); };
    root.querySelectorAll("[data-act]").forEach((b) =>
      (b.onclick = async () => {
        b.disabled = true;
        try {
          await adminApi("POST", "/admin/instances/" + b.dataset.iid + "/" + b.dataset.act);
          renderAdminDetail(id); // neu laden
        } catch (err) { alert(err.message); b.disabled = false; }
      })
    );
  }

  ({ login: renderLogin, register: renderRegister, konto: renderKonto, preise: renderPreise, admin: renderAdmin }[page] || renderLogin)();
})();
