import { execFile } from "child_process";
import { promisify } from "util";
import { readdir, rm, stat } from "fs/promises";
import { existsSync, mkdirSync } from "fs";
import path from "path";
import { Settings } from "@/models/Settings";
import { connectDB } from "@/lib/db";

const execFileAsync = promisify(execFile);

// Echtes mongodump statt der früheren handgestrickten EJSON-Lösung — die
// gab es nur, weil auf diesem Server bislang keine MongoDB-Tools installiert
// waren. Seit der Umstellung auf eine lokal selbst gehostete MongoDB
// (10.08.2026, siehe STATUS.md) sind `mongodump`/`mongorestore` Teil der
// Installation, damit jetzt der robustere, standardmäßige Weg mit
// vollständigem Index-Erhalt und garantiert wiederherstellbarem Format.
const BACKUP_ROOT = "/var/backups/rakku-v2-db";
const KEEP_LAST = 14;

function timestampName(date: Date) {
  return date.toISOString().replace(/[:.]/g, "-");
}

export async function runDatabaseBackup(): Promise<{ file: string; sizeBytes: number }> {
  if (!existsSync(BACKUP_ROOT)) mkdirSync(BACKUP_ROOT, { recursive: true });

  const now = new Date();
  const archivePath = path.join(BACKUP_ROOT, `${timestampName(now)}.archive.gz`);
  const uri = process.env.MONGODB_URI;
  if (!uri) throw new Error("MONGODB_URI ist nicht gesetzt.");

  await execFileAsync("mongodump", [`--uri=${uri}`, `--archive=${archivePath}`, "--gzip"]);

  await pruneOldBackups();

  await connectDB();
  await Settings.findOneAndUpdate({ key: "main" }, { lastBackupAt: now });

  const { size } = await stat(archivePath);
  return { file: archivePath, sizeBytes: size };
}

async function pruneOldBackups() {
  if (!existsSync(BACKUP_ROOT)) return;
  const entries = await readdir(BACKUP_ROOT);
  const withTimes = await Promise.all(
    entries.map(async (name) => ({ name, mtime: (await stat(path.join(BACKUP_ROOT, name))).mtimeMs }))
  );
  withTimes.sort((a, b) => b.mtime - a.mtime);
  const toDelete = withTimes.slice(KEEP_LAST);
  await Promise.all(toDelete.map((e) => rm(path.join(BACKUP_ROOT, e.name), { recursive: true, force: true })));
}
