import multer from "multer";
import crypto from "crypto";
import path from "path";
import fs from "fs";
import response from "../response.js";

const memoryStorage = multer.memoryStorage();

const fileFilter = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase();

  if (file.fieldname.startsWith("AUDIO")) {
    if (ext === ".mp3") {
      cb(null, true);
    } else {
      cb(
        new Error("Invalid file type, only .mp3 files are allowed for audio!"),
        false
      );
    }
  } else if (file.fieldname.startsWith("IMAGE")) {
    if (ext === ".jpg" || ext === ".jpeg" || ext === ".png") {
      cb(null, true);
    } else {
      cb(
        new Error(
          "Invalid file type, only .jpg, .jpeg, and .png files are allowed for image!"
        ),
        false
      );
    }
  } else {
    cb(new Error("Invalid file type!"), false);
  }
};

const upload = multer({
  storage: memoryStorage,
  fileFilter,
  limits: {
    fileSize: 100 * 1024 * 1024,
  },
}).any();

const handleUpload = (req, res, next) => {
  upload(req, res, (err) => {
    if (err) {
      return response(400, null, err.message, res);
    }

    const files = req.files || [];
    req.filesToSave = {};

    let validFiles = true;
    let errorMessages = [];

    files.forEach((file) => {
      if (file.fieldname.startsWith("AUDIO")) {
        if (file.size > 10 * 1024 * 1024) {
          validFiles = false;
          errorMessages.push(`Audio file exceeds the size limit of 10MB`);
        } else {
          req.filesToSave[file.fieldname] = file;
        }
      } else if (file.fieldname.startsWith("IMAGE")) {
        if (file.size > 5 * 1024 * 1024) {
          validFiles = false;
          errorMessages.push(`Image file exceeds the size limit of 5MB`);
        } else {
          req.filesToSave[file.fieldname] = file;
        }
      }
    });

    if (validFiles) {
      next();
    } else {
      clearFileBuffers(req.filesToSave);
      return response(400, null, errorMessages.join("; "), res);
    }
  });
};

export const clearFileBuffers = (files) => {
  for (const file of Object.values(files)) {
    if (file && file.buffer) {
      file.buffer = null;
    }
  }
};

export const generateHash = (levelId, filename, bufferLength) => {
  return crypto
    .createHash("md5")
    .update(levelId + filename + bufferLength)
    .digest("hex");
};

export const saveFileToDisk = (file, type, levelId, exerciseId) => {
  const ext = path.extname(file.originalname);
  const hash = generateHash(levelId, file.originalname, file.buffer.length);
  const filename = `${type}-${exerciseId}-${hash}${ext}`;

  let folderPath;
  switch (type) {
    case "AUDIO":
      folderPath = path.join("public/uploads/exercise/audio");
      break;
    case "IMAGE":
      folderPath = path.join("public/uploads/exercise/image");
      break;
    default:
      folderPath = path.join("public/uploads/exercise");
  }

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

  const filepath = path.join(folderPath, filename);
  fs.writeFileSync(filepath, file.buffer);
  return filename;
};

export default handleUpload;
