/* =====================================================================
   routes/supporter-admin.js — Administrationsbereich für das Supporter-
   Abo (Dogfather_VanVan_Supporter_Abo.odt Abschnitt 27). 1:1 portiert aus
   cloudflare-worker/src/routes/supporter-admin.js.

   Nutzt die BESTEHENDE interne Team-Session (auth.js/requireSession),
   NICHT die öffentliche Supporter-Session — nur berechtigte
   Administrator:innen (Owner oder Rolle mit SUPPORTER_*-Rechten) dürfen
   hierauf zugreifen.
   ===================================================================== */
import { db } from "../db.js";
import { generateId, nowIso } from "../lib/crypto.js";
import { hasPermission } from "../lib/permissions.js";
import { json } from "../lib/http.js";
import { logAction } from "../lib/audit.js";
import { computeProgress, timelineForCurrentCycle } from "../lib/supporter-cycle.js";

function can(session, key) {
  if (!session) return false;
  if (session.isOwner) return true;
  return hasPermission(session.permissions, session.overrides, key);
}

function forbidden(res) {
  return json(res, { ok: false, error: "Keine Berechtigung." }, 403);
}

/** Abonnentenübersicht mit Filtern (Abschnitt 27). */
export async function listSupporters(req, res, session) {
  if (!can(session, "SUPPORTER_VIEW")) return forbidden(res);
  const body = req.body || {};
  const filter = body.filter || "alle";

  const rows = db
    .prepare(
      `SELECT u.id, u.display_name, u.tiktok_username, u.email, u.email_verified, u.created_at,
              s.id as sub_id, s.paypal_subscription_id, s.status as sub_status, s.started_at,
              s.next_payment_at, s.paid_period_end_at, s.cancelled_at, s.total_paid_months
       FROM supporter_users u
       LEFT JOIN supporter_subscriptions s ON s.supporter_id = u.id
       WHERE u.status = 'active'
       ORDER BY u.created_at DESC`
    )
    .all();

  let list = rows;
  const FILTER_MAP = {
    aktiv: (r) => r.sub_status === "active",
    gekuendigt: (r) => r.sub_status === "cancelled",
    zahlung_fehlgeschlagen: (r) => r.sub_status === "suspended",
    monat_6: (r) => r.total_paid_months >= 6,
    monat_12: (r) => r.total_paid_months >= 12,
    monat_18: (r) => r.total_paid_months >= 18,
    monat_24: (r) => r.total_paid_months >= 24,
    monat_30: (r) => r.total_paid_months >= 30,
  };
  if (FILTER_MAP[filter]) list = list.filter(FILTER_MAP[filter]);

  // Fortschritt (Zyklus/Meilenstein) rein rechnerisch aus total_paid_months
  // ergänzen (Nutzer-Wunsch 04.08.2026: "wo die Leute mit den Abos dran
  // sind ... alles einsehen können") — dieselbe Logik wie im Supporter-
  // Bereich selbst (lib/supporter-cycle.js), damit nichts auseinanderläuft.
  list = list.map((r) => ({ ...r, progress: computeProgress(r.total_paid_months || 0) }));

  return json(res, { ok: true, supporters: list });
}

/**
 * Übersicht über ALLE Supporter hinweg (Nutzer-Wunsch 04.08.2026: "ein
 * festes Fenster, wo man drauf klicken muss um zu sehen wer was hat, wie
 * weit ist" — statt sich erst durch jeden einzelnen Supporter klicken zu
 * müssen). Liefert die komplette Prämien-Warteschlange (für den Versand)
 * und die letzten Zahlungen über alle Supporter, jeweils mit Name/E-Mail
 * dazu — bewusst EIN kombinierter Aufruf statt vieler Einzelabfragen.
 */
export async function getAdminOverview(req, res, session) {
  if (!can(session, "SUPPORTER_VIEW")) return forbidden(res);

  const premiums = db
    .prepare(
      `SELECT p.*, c.name as collection_name, u.display_name, u.email, u.tiktok_username
       FROM supporter_premiums p
       JOIN supporter_collections c ON c.id = p.collection_id
       JOIN supporter_users u ON u.id = p.supporter_id
       ORDER BY
         CASE p.redeem_status
           WHEN 'wird_geprueft' THEN 0
           WHEN 'wird_vorbereitet' THEN 1
           WHEN 'versandbereit' THEN 2
           WHEN 'problem' THEN 3
           WHEN 'ersatz_wird_vorbereitet' THEN 4
           WHEN 'verfuegbar' THEN 5
           WHEN 'versendet' THEN 6
           WHEN 'zugestellt' THEN 7
           WHEN 'erhalten' THEN 8
           ELSE 9
         END,
         p.unlocked_at DESC`
    )
    .all();

  const payments = db
    .prepare(
      `SELECT pay.*, u.display_name, u.email
       FROM supporter_payments pay
       JOIN supporter_users u ON u.id = pay.supporter_id
       ORDER BY pay.paid_at DESC LIMIT 100`
    )
    .all();

  return json(res, { ok: true, premiums, payments });
}

/** Details + Prämien eines einzelnen Supporters. */
export async function getSupporterDetail(req, res, session) {
  if (!can(session, "SUPPORTER_VIEW")) return forbidden(res);
  const body = req.body || {};
  const supporter = db.prepare(`SELECT * FROM supporter_users WHERE id = ?`).get(body.supporterId);
  if (!supporter) return json(res, { ok: false, error: "Nicht gefunden." }, 404);

  const sub = db
    .prepare(`SELECT * FROM supporter_subscriptions WHERE supporter_id = ? ORDER BY created_at DESC LIMIT 1`)
    .get(supporter.id);
  const premiums = db
    .prepare(
      `SELECT p.*, c.name as collection_name FROM supporter_premiums p
       JOIN supporter_collections c ON c.id = p.collection_id
       WHERE p.supporter_id = ? ORDER BY p.cycle_number, p.milestone_month`
    )
    .all(supporter.id);
  const payments = db.prepare(`SELECT * FROM supporter_payments WHERE supporter_id = ? ORDER BY paid_at DESC LIMIT 50`).all(supporter.id);

  const totalPaidMonths = sub?.total_paid_months || 0;
  const progress = computeProgress(totalPaidMonths);
  const timeline = timelineForCurrentCycle(totalPaidMonths);

  return json(res, {
    ok: true, supporter, subscription: sub, premiums, payments,
    progress, timeline,
  });
}

/** Prämie/Versand manuell bearbeiten (Abschnitt 27 "Prämienverwaltung"). */
export async function updatePremium(req, res, session) {
  if (!can(session, "SUPPORTER_MANAGE_PREMIUMS")) return forbidden(res);
  const body = req.body || {};
  const premium = db.prepare(`SELECT * FROM supporter_premiums WHERE id = ?`).get(body.premiumId);
  if (!premium) return json(res, { ok: false, error: "Prämie nicht gefunden." }, 404);

  const ALLOWED_STATUS = [
    "verfuegbar", "eingeloest", "wird_geprueft", "wird_vorbereitet",
    "versandbereit", "versendet", "zugestellt", "erhalten", "problem", "ersatz_wird_vorbereitet",
  ];
  const nextStatus = ALLOWED_STATUS.includes(body.redeemStatus) ? body.redeemStatus : premium.redeem_status;
  const trackingNumber = body.trackingNumber !== undefined ? body.trackingNumber : premium.tracking_number;
  const shippedAt = nextStatus === "versendet" && !premium.shipped_at ? nowIso() : premium.shipped_at;
  const deliveredAt = nextStatus === "zugestellt" && !premium.delivered_at ? nowIso() : premium.delivered_at;

  db.prepare(
    `UPDATE supporter_premiums SET redeem_status = ?, tracking_number = ?, shipped_at = ?, delivered_at = ?, admin_note = ? WHERE id = ?`
  ).run(nextStatus, trackingNumber || null, shippedAt, deliveredAt, body.adminNote ?? premium.admin_note, premium.id);

  logAction(session.actor, "supporter.premium_updated", premium.id, {
    from: premium.redeem_status, to: nextStatus,
  });
  return json(res, { ok: true });
}

/** Kollektionen anlegen/bearbeiten (Abschnitt 27 "Kollektionen verwalten"). */
export async function listCollections(req, res, session) {
  if (!can(session, "SUPPORTER_VIEW")) return forbidden(res);
  const rows = db.prepare(`SELECT * FROM supporter_collections ORDER BY collection_number ASC`).all();
  return json(res, { ok: true, collections: rows });
}

export async function upsertCollection(req, res, session) {
  if (!can(session, "SUPPORTER_MANAGE_COLLECTIONS")) return forbidden(res);
  const body = req.body || {};
  const num = Number(body.collectionNumber);
  if (!Number.isFinite(num) || num < 1) return json(res, { ok: false, error: "Ungültige Kollektionsnummer." }, 400);

  const existing = db.prepare(`SELECT id FROM supporter_collections WHERE collection_number = ?`).get(num);
  const id = existing?.id || generateId();
  const fields = {
    name: body.name || `Kollektion ${String(num).padStart(2, "0")}`,
    theme: body.theme || null,
    description: body.description || null,
    cover_image: body.coverImage || null,
    small_teddy_design: body.smallTeddyDesign || null,
    medium_teddy_design: body.mediumTeddyDesign || null,
    large_teddy_design: body.largeTeddyDesign || null,
    mug_design: body.mugDesign || null,
    card_design: body.cardDesign || null,
    hoodie_design: body.hoodieDesign || null,
    available_hoodie_sizes: JSON.stringify(body.availableHoodieSizes || ["S", "M", "L", "XL", "XXL"]),
    status: body.status === "published" ? "published" : "draft",
  };

  if (existing) {
    db.prepare(
      `UPDATE supporter_collections SET name=?, theme=?, description=?, cover_image=?, small_teddy_design=?,
         medium_teddy_design=?, large_teddy_design=?, mug_design=?, card_design=?, hoodie_design=?,
         available_hoodie_sizes=?, status=? WHERE id=?`
    ).run(
      fields.name, fields.theme, fields.description, fields.cover_image, fields.small_teddy_design,
      fields.medium_teddy_design, fields.large_teddy_design, fields.mug_design, fields.card_design,
      fields.hoodie_design, fields.available_hoodie_sizes, fields.status, id
    );
  } else {
    db.prepare(
      `INSERT INTO supporter_collections
         (id, collection_number, name, theme, description, cover_image, small_teddy_design, medium_teddy_design,
          large_teddy_design, mug_design, card_design, hoodie_design, available_hoodie_sizes, status, created_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    ).run(
      id, num, fields.name, fields.theme, fields.description, fields.cover_image, fields.small_teddy_design,
      fields.medium_teddy_design, fields.large_teddy_design, fields.mug_design, fields.card_design,
      fields.hoodie_design, fields.available_hoodie_sizes, fields.status, nowIso()
    );
  }

  logAction(session.actor, "supporter.collection_saved", id, { collectionNumber: num });
  return json(res, { ok: true, id });
}
