import multer from "multer";
import sharp from "sharp";
import path from "path";
import fs from "fs";
import type { NextFunction, Request, Response } from "express";

// const UPLOAD_DIR = "uploads";
const ALLOWED_EXT = [".jpg", ".jpeg", ".png", ".webp"];

// const ensureDir = () => {
//   const uploadPath = path.join(process.cwd(), UPLOAD_DIR);
//   if (!fs.existsSync(uploadPath)) {
//     fs.mkdirSync(uploadPath, { recursive: true });
//   }
//   return uploadPath;
// };

// const storage = multer.diskStorage({
//   destination: (req, file, cb) => {
//     cb(null, ensureDir());
//   },

//   filename: (req, file, cb) => {
//     const ext = path.extname(file.originalname).toLowerCase();
//     const baseName = path
//       .basename(file.originalname, ext)
//       .replace(/\s+/g, "_");

//     const uploadPath = ensureDir();

//     let finalName = `${baseName}${ext}`;
//     let counter = 1;

//     while (fs.existsSync(path.join(uploadPath, finalName))) {
//       finalName = `${baseName}_(${counter})${ext}`;
//       counter++;
//     }

//     cb(null, finalName);
//   },
// });

const UPLOAD_ROOT = "uploads";

const ensureDir = (subDir?: string) => {
  const uploadPath = path.join(
    process.cwd(),
    UPLOAD_ROOT,
    subDir ?? ""
  );

  if (!fs.existsSync(uploadPath)) {
    fs.mkdirSync(uploadPath, { recursive: true });
  }

  return uploadPath;
};

const createStorage = (subDir?: string) =>
  multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, ensureDir(subDir));
    },

    filename: (req, file, cb) => {
      const ext = path.extname(file.originalname).toLowerCase();
      const baseName = path
        .basename(file.originalname, ext)
        .trim()
        .replace(/\s+/g, "_")
        .replace(/[^a-zA-Z0-9._-]/g, "");
      const uploadPath = ensureDir(subDir);

      let finalName = `${baseName}${ext}`;
      let counter = 1;

      while (fs.existsSync(path.join(uploadPath, finalName))) {
        finalName = `${baseName}_(${counter})${ext}`;
        counter++;
      }

      cb(null, finalName);
    },
  });

const fileFilter: multer.Options["fileFilter"] = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase();
  if (!ALLOWED_EXT.includes(ext)) {
    return cb(new Error("INVALID_FILE_TYPE"));
  }
  cb(null, true);
};

export const imageUpload = (subDir?: string) =>
  multer({
    storage: createStorage(subDir),
    fileFilter,
    limits: { fileSize: 5 * 1024 * 1024 },
  });

const syllabusFileFilter: multer.Options["fileFilter"] = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase();
  if (ext !== ".pdf") {
    return cb(new Error("INVALID_FILE_TYPE_ONLY_PDF_ALLOWED"));
  }
  cb(null, true);
};

export const syllabusUpload = multer({
  storage: createStorage("syllabus"),
  fileFilter: syllabusFileFilter,
  limits: { fileSize: 10 * 1024 * 1024 },
});

const notificationFileFilter: multer.Options["fileFilter"] = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase();
  const allowed = [".pdf", ".jpg", ".jpeg", ".png", ".webp"];
  if (!allowed.includes(ext)) {
    return cb(new Error("INVALID_FILE_TYPE"));
  }
  cb(null, true);
};

export const notificationUpload = multer({
  storage: createStorage("notification"),
  fileFilter: notificationFileFilter,
  limits: { fileSize: 10 * 1024 * 1024 },
});

const excelFileFilter: multer.Options["fileFilter"] = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase();
  const allowed = [".xlsx", ".xls"];
  if (!allowed.includes(ext)) {
    return cb(new Error("INVALID_FILE_TYPE_ONLY_EXCEL_ALLOWED"));
  }
  cb(null, true);
};

export const excelUpload = multer({
  storage: createStorage("excel"),
  fileFilter: excelFileFilter,
  limits: { fileSize: 5 * 1024 * 1024 },
});

const notesFileFilter: multer.Options["fileFilter"] = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase();
  if (ext !== ".pdf") {
    return cb(new Error("INVALID_FILE_TYPE_ONLY_PDF_ALLOWED"));
  }
  cb(null, true);
};

export const notesUpload = multer({
  storage: createStorage("notespdf"),
  fileFilter: notesFileFilter,
  limits: { fileSize: 3 * 1024 * 1024 },
});

/**
 * Sharp image optimizer middleware
 */
export const optimizeImage = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  try {
    // 👇 req.files is an OBJECT when using upload.fields()
    const filesMap = req.files as {
      [fieldname: string]: Express.Multer.File[];
    };

    if (!filesMap) return next();

    // Flatten object → array safely
    const files: Express.Multer.File[] = Object.values(filesMap).flat();

    if (!files.length) return next();

    for (const file of files) {
      const ext = path.extname(file.filename).toLowerCase();
      const inputPath = file.path;
      const tempPath = inputPath + ".tmp";

      const image = sharp(inputPath).resize({
        width: 1600,
        withoutEnlargement: true,
      });

      if (ext === ".jpg" || ext === ".jpeg") {
        await image.jpeg({ quality: 80 }).toFile(tempPath);
      } else if (ext === ".png") {
        await image.png({ compressionLevel: 8 }).toFile(tempPath);
      } else if (ext === ".webp") {
        await image.webp({ quality: 80 }).toFile(tempPath);
      } else {
        continue;
      }

      fs.unlinkSync(inputPath);
      fs.renameSync(tempPath, inputPath);
    }

    next();
  } catch (err) {
    next(err);
  }
};
