import { createReadStream } from 'node:fs';
import { stat } from 'node:fs/promises';
import { Readable } from 'node:stream';

import { NextResponse } from 'next/server';

import { requireSuperAdmin, withAuth } from '@/lib/api/helpers';
import { createAuditLog } from '@/lib/audit';
import { errorResponse } from '@/lib/errors';
import { createFullBackupTar } from '@/lib/services/backup-export.service';

export const runtime = 'nodejs';
// A full backup pg_dumps the DB and streams every blob; on a large dataset the
// assembly phase can run for a while before the download starts. Lift the
// platform timeout accordingly (no-op on hosts without a hard cap).
export const maxDuration = 3600;

/**
 * Stream a full disaster-recovery bundle (db.dump + all blobs + manifest.json)
 * as a tar download. Super-admin only — this egresses every tenant's data.
 *
 * The bundle is assembled to a temp file first, so any failure (pg_dump,
 * storage read) surfaces as a clean JSON error *before* the download begins
 * rather than as a truncated tar. The temp file is removed once the response
 * stream closes (including on client disconnect).
 */
export const GET = withAuth(async (_req, ctx) => {
  try {
    requireSuperAdmin(ctx, 'admin.backup.export');

    const { tarPath, filename, manifest, cleanup } = await createFullBackupTar();

    await createAuditLog({
      userId: ctx.userId,
      portId: ctx.portId,
      action: 'backup_export',
      entityType: 'system_backup',
      entityId: filename,
      severity: 'warning',
      source: 'user',
      ipAddress: ctx.ipAddress,
      userAgent: ctx.userAgent,
      metadata: {
        storageBackend: manifest.storageBackend,
        blobs: manifest.counts.blobs,
        blobBytes: manifest.counts.blobBytes,
        skipped: manifest.counts.skipped,
        dbDumpBytes: manifest.database.sizeBytes,
      },
    });

    const { size } = await stat(tarPath);
    const nodeStream = createReadStream(tarPath);
    // Remove the temp tar once it's been fully sent or the client bails.
    nodeStream.on('close', () => void cleanup());
    nodeStream.on('error', () => void cleanup());

    const webStream = Readable.toWeb(nodeStream) as ReadableStream<Uint8Array>;
    return new NextResponse(webStream, {
      status: 200,
      headers: {
        'Content-Type': 'application/x-tar',
        'Content-Length': String(size),
        'Content-Disposition': `attachment; filename="${filename}"`,
        'Cache-Control': 'no-store',
      },
    });
  } catch (error) {
    return errorResponse(error);
  }
});
