import { NextRequest, NextResponse } from "next/server";
import fs from "fs";
import path from "path";
import { Readable } from "stream";
import {
  readMetadata, getUploadsDir, isInlineSafe, safeUploadPath, thumbPathFor,
} from "@/lib/store";

export async function GET(
  req: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id }       = await params;
  const isThumb      = req.nextUrl.searchParams.get("thumb") === "1";
  const wantDownload = req.nextUrl.searchParams.get("download") === "1";
  const metadata     = readMetadata();
  const file         = metadata.files[id];

  if (!file) return NextResponse.json({ error: "Not found" }, { status: 404 });

  // Thumbnail variant: served with long cache, always image/webp
  if (isThumb) {
    const tp = thumbPathFor(id);
    if (!fs.existsSync(tp)) {
      return NextResponse.json({ error: "No thumbnail" }, { status: 404 });
    }
    const stat = fs.statSync(tp);
    const stream = fs.createReadStream(tp);
    return new Response(Readable.toWeb(stream) as ReadableStream, {
      status: 200,
      headers: {
        "Content-Type":   "image/webp",
        "Content-Length": stat.size.toString(),
        "Cache-Control":  "private, max-age=86400, immutable",
      },
    });
  }

  const storedName = file.storedName ?? (id + path.extname(file.originalName));
  const filePath   = safeUploadPath(storedName);

  if (!filePath || !fs.existsSync(filePath)) {
    return NextResponse.json({ error: "File missing" }, { status: 404 });
  }

  const stat        = fs.statSync(filePath);
  const totalSize   = stat.size;
  const contentType = file.type || "application/octet-stream";
  const encodedName = encodeURIComponent(file.originalName);

  // Force attachment for anything not on the inline-safe whitelist.
  // This neutralizes stored XSS via SVG / HTML / JS uploads.
  const dispositionType = wantDownload || !isInlineSafe(contentType) ? "attachment" : "inline";
  const disposition     = `${dispositionType}; filename*=UTF-8''${encodedName}`;

  // Range request handling (e.g. for video seeking, partial PDF loads).
  const range = req.headers.get("range");
  if (range) {
    const m = /^bytes=(\d*)-(\d*)$/.exec(range);
    if (m) {
      const start = m[1] ? parseInt(m[1], 10) : 0;
      const end   = m[2] ? parseInt(m[2], 10) : totalSize - 1;
      if (Number.isNaN(start) || Number.isNaN(end) || start > end || end >= totalSize) {
        return new Response(null, {
          status: 416,
          headers: { "Content-Range": `bytes */${totalSize}` },
        });
      }
      const stream = fs.createReadStream(filePath, { start, end });
      return new Response(Readable.toWeb(stream) as ReadableStream, {
        status: 206,
        headers: {
          "Content-Type":        contentType,
          "Content-Disposition": disposition,
          "Content-Range":       `bytes ${start}-${end}/${totalSize}`,
          "Accept-Ranges":       "bytes",
          "Content-Length":      (end - start + 1).toString(),
          "Cache-Control":       "private, max-age=3600",
          "X-Content-Type-Options": "nosniff",
        },
      });
    }
  }

  const stream = fs.createReadStream(filePath);
  return new Response(Readable.toWeb(stream) as ReadableStream, {
    status: 200,
    headers: {
      "Content-Type":           contentType,
      "Content-Disposition":    disposition,
      "Content-Length":         totalSize.toString(),
      "Accept-Ranges":          "bytes",
      "Cache-Control":          "private, max-age=3600",
      "X-Content-Type-Options": "nosniff",
    },
  });
}
