import fs from "node:fs/promises";
import path from "node:path";
import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";
import { hasPermission } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import {
  documentContentType,
  documentUrlCandidates,
  isAllowedDocumentExtension,
  isSimpleDocumentFileName,
  safeDecodeDocumentFileName
} from "@/lib/documents";

const notFoundMessage = "Document file not found. Please upload again.";

type RouteContext = {
  params: Promise<{ fileName: string }>;
};

async function isOwnedDocument(fileName: string, userId: string) {
  const candidates = documentUrlCandidates(fileName);
  const document = await prisma.document.findFirst({
    where: {
      fileUrl: { in: candidates }
    },
    select: { projectId: true }
  });
  if (document) return hasPermission(userId, document.projectId, "documents.view");

  const documentFile = await prisma.documentFile.findFirst({
    where: { fileUrl: { in: candidates } },
    select: { document: { select: { projectId: true } } }
  });
  return documentFile ? hasPermission(userId, documentFile.document.projectId, "documents.view") : false;
}

async function buildDocumentResponse(fileNameParam: string, includeBody: boolean) {
  const user = await getCurrentUser();
  if (!user) {
    return new NextResponse("Please sign in to view this document.", { status: 401 });
  }

  const decodedName = safeDecodeDocumentFileName(fileNameParam);
  if (!isSimpleDocumentFileName(decodedName) || !isAllowedDocumentExtension(decodedName)) {
    return new NextResponse("Invalid document file.", { status: 400 });
  }

  const owned = await isOwnedDocument(decodedName, user.id);
  if (!owned) {
    return new NextResponse(notFoundMessage, { status: 404 });
  }

  const uploadsDir = path.join(process.cwd(), "public", "uploads", "documents");
  const filePath = path.join(uploadsDir, decodedName);

  try {
    const stats = await fs.stat(filePath);
    if (!stats.isFile()) {
      return new NextResponse(notFoundMessage, { status: 404 });
    }

    const headers = {
      "Content-Type": documentContentType(decodedName),
      "Content-Disposition": `inline; filename="${decodedName.replace(/"/g, "")}"`,
      "Cache-Control": "private, max-age=0, must-revalidate",
      "Content-Length": String(stats.size)
    };

    if (!includeBody) return new NextResponse(null, { headers });

    const bytes = await fs.readFile(filePath);
    const body = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;
    return new NextResponse(body, { headers });
  } catch {
    return new NextResponse(notFoundMessage, { status: 404 });
  }
}

export async function GET(_request: Request, { params }: RouteContext) {
  const { fileName } = await params;
  return buildDocumentResponse(fileName, true);
}

export async function HEAD(_request: Request, { params }: RouteContext) {
  const { fileName } = await params;
  return buildDocumentResponse(fileName, false);
}
