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 {
  isAllowedReceiptExtension,
  isSimpleReceiptFileName,
  receiptContentType,
  receiptUrlCandidates,
  safeDecodeReceiptFileName
} from "@/lib/receipts";

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

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

async function findOwnedReceipt(fileName: string, userId: string) {
  const candidateUrls = receiptUrlCandidates(fileName);

  const fileRecord = await prisma.fileRecord.findFirst({
    where: {
      fileUrl: { in: candidateUrls }
    },
    select: { projectId: true }
  });
  if (fileRecord) return hasPermission(userId, fileRecord.projectId, "receipts.view");

  const expense = await prisma.expense.findFirst({
    where: {
      receiptUrl: { in: candidateUrls }
    },
    select: { projectId: true }
  });

  return expense ? hasPermission(userId, expense.projectId, "receipts.view") : false;
}

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

  const decodedName = safeDecodeReceiptFileName(fileNameParam);
  if (!isSimpleReceiptFileName(decodedName) || !isAllowedReceiptExtension(decodedName)) {
    return new NextResponse("Invalid receipt file.", { status: 400 });
  }

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

  const uploadsDir = path.join(process.cwd(), "public", "uploads", "receipts");
  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": receiptContentType(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 buildReceiptResponse(fileName, true);
}

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