import { BadRequestException } from "@nestjs/common";
import { extname } from "path";

export type UploadType = "foto" | "firma" | "pdf";

interface UploadRule {
  maxSize: number;
  allowedExtensions: string[];
  mimePattern: RegExp;
  invalidTypeMessage: string;
  tooLargeMessage: string;
}

export const UPLOAD_RULES: Record<UploadType, UploadRule> = {
  foto: {
    maxSize: 8 * 1024 * 1024,
    allowedExtensions: [".jpg", ".jpeg", ".png", ".webp", ".gif"],
    mimePattern: /^image\/(jpeg|png|webp|gif)$/i,
    invalidTypeMessage: "La foto debe ser una imagen JPG, PNG, WEBP o GIF.",
    tooLargeMessage:
      "La foto es demasiado grande. Intenta con una imagen mas liviana.",
  },
  firma: {
    maxSize: 3 * 1024 * 1024,
    allowedExtensions: [".jpg", ".jpeg", ".png", ".webp"],
    mimePattern: /^image\/(jpeg|png|webp)$/i,
    invalidTypeMessage: "La firma debe ser una imagen JPG, PNG o WEBP.",
    tooLargeMessage:
      "La firma es demasiado grande. Intenta capturarla de nuevo.",
  },
  pdf: {
    maxSize: 15 * 1024 * 1024,
    allowedExtensions: [".pdf"],
    mimePattern: /^application\/pdf$/i,
    invalidTypeMessage: "El archivo debe ser PDF.",
    tooLargeMessage:
      "El PDF es demasiado grande. El tamano maximo permitido es 15 MB.",
  },
};

export function getUploadRule(type: string): UploadRule {
  const rule = UPLOAD_RULES[type as UploadType];
  if (!rule) {
    throw new BadRequestException("Tipo de archivo no soportado.");
  }
  return rule;
}

export function isAllowedUploadType(
  file: Pick<Express.Multer.File, "mimetype" | "originalname">,
  type: UploadType,
): boolean {
  const rule = getUploadRule(type);
  const extension = extname(file.originalname || "").toLowerCase();
  return (
    rule.mimePattern.test(file.mimetype || "") &&
    rule.allowedExtensions.includes(extension)
  );
}

export function assertUploadedFile(
  file: Express.Multer.File | undefined,
  type: UploadType,
): asserts file is Express.Multer.File {
  const rule = getUploadRule(type);

  if (!file) {
    throw new BadRequestException("Selecciona un archivo para subir.");
  }

  if (!isAllowedUploadType(file, type)) {
    throw new BadRequestException(rule.invalidTypeMessage);
  }

  if (file.size > rule.maxSize) {
    throw new BadRequestException(rule.tooLargeMessage);
  }

  if (type === "pdf") {
    const startsWithPdfSignature =
      file.buffer?.subarray(0, 5).toString("utf8") === "%PDF-";
    if (!startsWithPdfSignature) {
      throw new BadRequestException("El archivo debe ser PDF.");
    }
  }
}
