import { Prisma } from "@prisma/client";
import { NextResponse } from "next/server";
import { requireAdminApiUser } from "@/lib/auth/admin";
import { prisma } from "@/lib/prisma";
import { readStoredProposalDocument, removeStoredProposalDocument } from "@/lib/proposals/storage";

export const runtime = "nodejs";

function isSchemaNotReadyError(error: unknown) {
  return error instanceof Prisma.PrismaClientKnownRequestError && (error.code === "P2021" || error.code === "P2022");
}

function safeContentDispositionFilename(value: string) {
  const normalized = value.trim().replace(/[\r\n"]/g, "_");
  return normalized || "documento";
}

function mapDocumentReadError(error: unknown) {
  if (!(error instanceof Error)) {
    return null;
  }

  if (error.message === "PROPOSAL_DOCUMENT_NOT_FOUND") {
    return { status: 404, message: "Archivo no encontrado en almacenamiento." };
  }

  if (error.message === "PROPOSAL_DOCUMENT_INVALID_PATH") {
    return { status: 400, message: "Ruta de almacenamiento invalida." };
  }

  if (error.message === "PROPOSAL_DOCUMENT_EMPTY") {
    return { status: 400, message: "Archivo vacio en almacenamiento." };
  }

  if (error.message === "PROPOSAL_DOCUMENT_TOO_LARGE") {
    return { status: 400, message: "Archivo excede el limite permitido." };
  }

  return null;
}

async function getOwnedProposalDocument(params: { userId: string; proposalId: string; documentId: string }) {
  return prisma.proposalDocument.findFirst({
    where: {
      id: params.documentId,
      proposalId: params.proposalId,
      userId: params.userId,
    },
    select: {
      id: true,
      fileName: true,
      filePath: true,
      mimeType: true,
    },
  });
}

export async function GET(_: Request, context: { params: Promise<{ id: string; documentId: string }> }) {
  const user = await requireAdminApiUser();

  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const { id, documentId } = await context.params;

    const document = await getOwnedProposalDocument({
      userId: user.id,
      proposalId: id,
      documentId,
    });

    if (!document) {
      return NextResponse.json({ error: "Documento no encontrado." }, { status: 404 });
    }

    let fileBuffer: Buffer;
    try {
      fileBuffer = await readStoredProposalDocument(document.filePath);
    } catch (error) {
      const mapped = mapDocumentReadError(error);
      if (mapped) {
        return NextResponse.json({ error: mapped.message }, { status: mapped.status });
      }

      throw error;
    }

    const encodedFilename = encodeURIComponent(document.fileName);
    return new NextResponse(new Uint8Array(fileBuffer), {
      status: 200,
      headers: {
        "Content-Type": document.mimeType || "application/octet-stream",
        "Content-Disposition": `attachment; filename="${safeContentDispositionFilename(document.fileName)}"; filename*=UTF-8''${encodedFilename}`,
        "Cache-Control": "no-store",
      },
    });
  } catch (error) {
    if (isSchemaNotReadyError(error)) {
      return NextResponse.json(
        { error: "La base de datos aun no tiene las tablas de Gestion de Licitaciones. Ejecuta prisma migrate para continuar." },
        { status: 503 },
      );
    }

    return NextResponse.json({ error: "No fue posible descargar el documento." }, { status: 400 });
  }
}

export async function DELETE(_: Request, context: { params: Promise<{ id: string; documentId: string }> }) {
  const user = await requireAdminApiUser();

  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const { id, documentId } = await context.params;

    const document = await getOwnedProposalDocument({
      userId: user.id,
      proposalId: id,
      documentId,
    });

    if (!document) {
      return NextResponse.json({ error: "Documento no encontrado." }, { status: 404 });
    }

    await removeStoredProposalDocument(document.filePath);
    await prisma.proposalDocument.delete({ where: { id: document.id } });

    return NextResponse.json({ ok: true });
  } catch (error) {
    if (isSchemaNotReadyError(error)) {
      return NextResponse.json(
        { error: "La base de datos aun no tiene las tablas de Gestion de Licitaciones. Ejecuta prisma migrate para continuar." },
        { status: 503 },
      );
    }

    return NextResponse.json({ error: "No fue posible eliminar el documento." }, { status: 400 });
  }
}
