import { NextResponse } from 'next/server';
import { spawn } from 'node:child_process';
import { mkdir, stat, unlink, rename } from 'node:fs/promises';
import { createWriteStream } from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import { checkSystemBin } from '@/lib/system-bins';

export const dynamic = 'force-dynamic';
export const maxDuration = 600;

const PROJECT_ROOT = process.cwd();
const DATA_DIR = path.join(PROJECT_ROOT, 'data');
const FACTORY_DIR = path.join(PROJECT_ROOT, 'factory');
const PRESET_PATH = path.join(FACTORY_DIR, 'preset.zip');

// GET — stato del preset (per UI: presente o no, dimensione, data).
export async function GET() {
  try {
    const s = await stat(PRESET_PATH);
    return NextResponse.json({
      exists: true,
      sizeBytes: s.size,
      modifiedAt: s.mtime.toISOString(),
    });
  } catch {
    return NextResponse.json({ exists: false });
  }
}

// POST — crea il preset zippando lo stato corrente di data/.
export async function POST() {
  if (!(await checkSystemBin('zip', '-v'))) {
    return NextResponse.json({ error: "Binario 'zip' non disponibile sul server." }, { status: 503 });
  }
  await mkdir(FACTORY_DIR, { recursive: true });

  // Scrive prima su .tmp poi rename atomico → mai un preset.zip parziale leggibile.
  const tmpPath = path.join(FACTORY_DIR, `preset.zip.${crypto.randomUUID()}.tmp`);

  const child = spawn(
    'zip',
    ['-r', '-', 'cards.txt', 'portals.txt', 'uploads', 'fonts', '-x', 'uploads/.tmp/*'],
    { cwd: DATA_DIR },
  );

  const out = createWriteStream(tmpPath);
  child.stdout.pipe(out);

  const exit: number = await new Promise(resolve => {
    let exitCode = -1;
    child.on('error', () => resolve(-1));
    child.on('exit', code => { exitCode = code ?? -1; });
    out.on('finish', () => resolve(exitCode));
    out.on('error', () => resolve(-1));
  });

  // 0 = ok, 12 = "nothing to do" (data/ vuoto: accettiamo, sarà uno zip minimale)
  if (exit !== 0 && exit !== 12) {
    try { await unlink(tmpPath); } catch { /* ignore */ }
    return NextResponse.json({ error: `zip terminato con codice ${exit}` }, { status: 500 });
  }

  await rename(tmpPath, PRESET_PATH);
  const s = await stat(PRESET_PATH);
  return NextResponse.json({
    ok: true,
    sizeBytes: s.size,
    modifiedAt: s.mtime.toISOString(),
  });
}
