import { NextRequest, NextResponse } from "next/server";
import { writeFile } from "fs/promises";
import fs from "fs";
import path from "path";
import PDFDocument from "pdfkit";
import {
  readMetadata, writeMetadata, getUploadsDir,
  isAllowedMime, sanitizeFilename, generateId, safeUploadPath,
} from "@/lib/store";
import { generatePdfThumbnail } from "@/lib/thumbnail";
import { DocFile } from "@/lib/types";

const MAX_BYTES_PER_FILE = 200 * 1024 * 1024; // 200 MB

function uniqueStoredName(uploadsDir: string, filename: string): string {
  const ext      = path.extname(filename);
  const baseName = path.basename(filename, ext);
  let candidate  = filename;
  let counter    = 1;
  // Bound the loop to avoid pathological collisions.
  while (counter < 10_000 && fs.existsSync(path.join(uploadsDir, candidate))) {
    candidate = `${baseName}_${counter}${ext}`;
    counter++;
  }
  return candidate;
}

function imageToPdf(imageBuffer: Buffer): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const doc    = new PDFDocument({ autoFirstPage: false, margin: 0 });
    const chunks: Buffer[] = [];
    doc.on("data",  c => chunks.push(c));
    doc.on("end",   () => resolve(Buffer.concat(chunks)));
    doc.on("error", reject);

    doc.addPage({ size: "A4", margin: 0 });
    const margin = 30;
    const w = doc.page.width  - margin * 2;
    const h = doc.page.height - margin * 2;
    doc.image(imageBuffer, margin, margin, { fit: [w, h], align: "center", valign: "center" });
    doc.end();
  });
}

export async function POST(req: NextRequest) {
  const formData = await req.formData();
  const files    = formData.getAll("files") as File[];

  if (!files.length) {
    return NextResponse.json({ error: "No files provided" }, { status: 400 });
  }

  const metadata   = readMetadata();
  const uploadsDir = getUploadsDir();
  const added: DocFile[] = [];
  const rejected: { name: string; reason: string }[] = [];

  for (const file of files) {
    if (file.size > MAX_BYTES_PER_FILE) {
      rejected.push({ name: file.name, reason: "Datei zu groß (max. 200 MB)" });
      continue;
    }

    const incomingType = file.type || "application/octet-stream";
    if (!isAllowedMime(incomingType)) {
      rejected.push({ name: file.name, reason: `Dateityp nicht erlaubt: ${incomingType}` });
      continue;
    }

    const id      = generateId();
    const isImage = incomingType === "image/jpeg" || incomingType === "image/png" || incomingType === "image/webp";
    let   buffer: Buffer = Buffer.from(await file.arrayBuffer()) as Buffer;
    let   storedType    = incomingType;
    let   safeName      = sanitizeFilename(file.name, path.extname(file.name) || "");

    if (isImage) {
      buffer     = await imageToPdf(buffer);
      storedType = "application/pdf";
      const baseName = path.basename(safeName, path.extname(safeName));
      safeName       = sanitizeFilename(baseName + ".pdf", ".pdf");
    }

    // Final safety: ensure the resolved write path stays inside uploadsDir.
    const candidate = uniqueStoredName(uploadsDir, safeName);
    const target    = safeUploadPath(candidate);
    if (!target) {
      rejected.push({ name: file.name, reason: "Ungültiger Dateiname" });
      continue;
    }

    await writeFile(target, buffer);

    let hasThumbnail = false;
    if (storedType === "application/pdf") {
      hasThumbnail = await generatePdfThumbnail(buffer, id);
    }

    const docFile: DocFile = {
      id,
      name:         candidate,
      originalName: file.name,
      storedName:   candidate,
      size:         buffer.byteLength,
      type:         storedType,
      uploadedAt:   new Date().toISOString(),
      categoryId:   null,
      tags:         [],
      starred:      false,
      hasThumbnail,
    };

    metadata.files[id] = docFile;
    added.push(docFile);
  }

  writeMetadata(metadata);
  return NextResponse.json({ files: added, rejected });
}
