const fs = require('fs');
const path = require('path');
const sharp = require('sharp');
const { resizeImageBuffer } = require('./resize');
const { getStrategyFunctions } = require('../strategies');
const { logger } = require('~/config');

/**
 * Converts an image file or buffer to target output type with specified resolution.
 *
 * @param {Express.Request} req - The request object, containing user and app configuration data.
 * @param {Buffer | Express.Multer.File} file - The file object, containing either a path or a buffer.
 * @param {'low' | 'high'} [resolution='high'] - The desired resolution for the output image.
 * @param {string} [basename=''] - The basename of the input file, if it is a buffer.
 * @returns {Promise<{filepath: string, bytes: number, width: number, height: number}>} An object containing the path, size, and dimensions of the converted image.
 * @throws Throws an error if there is an issue during the conversion process.
 */
async function convertImage(req, file, resolution = 'high', basename = '') {
  try {
    let inputBuffer;
    let outputBuffer;
    let extension = path.extname(file.path ?? basename).toLowerCase();

    // Check if the input is a buffer or a file path
    if (Buffer.isBuffer(file)) {
      inputBuffer = file;
    } else if (file && file.path) {
      const inputFilePath = file.path;
      inputBuffer = await fs.promises.readFile(inputFilePath);
    } else {
      throw new Error('Invalid input: file must be a buffer or contain a valid path.');
    }

    // Resize the image buffer
    const {
      buffer: resizedBuffer,
      width,
      height,
    } = await resizeImageBuffer(inputBuffer, resolution);

    // Check if the file is already in target format; if it isn't, convert it:
    const targetExtension = `.${req.app.locals.imageOutputType}`;
    if (extension === targetExtension) {
      outputBuffer = resizedBuffer;
    } else {
      outputBuffer = await sharp(resizedBuffer).toFormat(req.app.locals.imageOutputType).toBuffer();
      extension = targetExtension;
    }

    // Generate a new filename for the output file
    const newFileName =
      path.basename(file.path ?? basename, path.extname(file.path ?? basename)) + extension;

    const { saveBuffer } = getStrategyFunctions(req.app.locals.fileStrategy);

    const savedFilePath = await saveBuffer({
      userId: req.user.id,
      buffer: outputBuffer,
      fileName: newFileName,
    });

    const bytes = Buffer.byteLength(outputBuffer);
    return { filepath: savedFilePath, bytes, width, height };
  } catch (err) {
    logger.error(err);
    throw err;
  }
}

module.exports = { convertImage };
