import { randomBytes } from "crypto";
import * as path from "path";

import multer, { FileFilterCallback } from "multer";

// The real poster-hosting path (per EventCentral's README: "the real
// contract has the *upstream backend* host posters and hand backend/ a
// sourceUrl"). backend/'s ALLOWED_POSTER_ORIGINS must include this
// service's own public URL for backend/ to accept URLs pointing here.
export const UPLOAD_DIR = path.join(__dirname, "..", "uploads");

// Same limits as backend/src/posterHandler.ts, which re-validates these
// independently once it downloads the file -- this is just to reject
// obviously-wrong uploads early, not the authoritative check.
export const ALLOWED_CONTENT_TYPES = ["image/png", "image/jpeg"];
export const MAX_FILE_SIZE_IN_BYTES = 15 * 1_000_000;

const EXTENSION_BY_CONTENT_TYPE: Record<string, string> = {
  "image/png": ".png",
  "image/jpeg": ".jpg",
};

const fileFilter = (_req: unknown, file: Express.Multer.File, callback: FileFilterCallback) => {
  if (!ALLOWED_CONTENT_TYPES.includes(file.mimetype)) {
    callback(new Error(`Unsupported file type "${file.mimetype}"`));
    return;
  }
  callback(null, true);
};

// Never trust the uploader-supplied original filename for the on-disk name
// -- multer's diskStorage does no sanitization of it, so a name containing
// ".." path segments could write outside UPLOAD_DIR (same issue found and
// fixed in backend/src/uploadRoute.ts). Generate our own name instead; the
// extension comes from the fileFilter-checked mimetype, never from the
// untrusted original filename.
function generateSafeFilename(mimetype: string): string {
  const extension = EXTENSION_BY_CONTENT_TYPE[mimetype] ?? "";
  return `${randomBytes(16).toString("hex")}${extension}`;
}

const storage = multer.diskStorage({
  destination: UPLOAD_DIR,
  filename: (_req, file, callback) => callback(null, generateSafeFilename(file.mimetype)),
});

// Exported as the multer instance (not a pre-built router) so server.ts can
// put it behind requireOidcSession/requireTeamAccess the same way /submit
// is -- this upload endpoint carries the same "must be a logged-in,
// team-verified user" requirement, unlike backend/'s dev-only equivalent.
export const upload = multer({ storage, fileFilter, limits: { fileSize: MAX_FILE_SIZE_IN_BYTES } });

export interface UploadedPoster {
  sourceUrl: string;
  filename: string;
  contentType: string;
}

export function describeUploadedFile(file: Express.Multer.File, publicBaseUrl: string): UploadedPoster {
  return {
    sourceUrl: `${publicBaseUrl}/uploads/${file.filename}`,
    filename: file.filename,
    contentType: file.mimetype,
  };
}
