const upload = require("../middlewares/upload");
// const uploadPhysical = require("../middlewares/upload_physical");
const dbConfig = require("../config/db.config");
const MongoClient = require("mongodb").MongoClient;
const GridFSBucket = require("mongodb").GridFSBucket;
const util = require("util");
var fs = require('fs');
var multer = require('multer');
const path = require("path");
const url = dbConfig.url;
const baseUrl = dbConfig.fileUrl;
const mongoClient = new MongoClient(url);

const readdir = util.promisify(fs.readdir);
const stat = util.promisify(fs.stat);

const uploadFiles = async (req, res) => {
  try {
    await upload(req, res);
    if (req.file == undefined) {
      return res.send({
        message: "You must select a file.",
      });
    }
    return res.send({
      message: "File has been uploaded.",
    });
  } catch (error) {
    console.log(error);
    return res.send({
      message: "Error when trying upload image: ${error}",
    });
  }
};
const getFile = async (req, res) => {
  try {
    await mongoClient.connect();
    const database = mongoClient.db(dbConfig.database);
    const images = database.collection(dbConfig.imgBucket + ".files");
    const chunks = database.collection(dbConfig.imgBucket + ".chunks");
    const cursor = await (images.find({filename: req.params.name}).toArray());
    if (cursor.length === 0) {
      return res.status(500).send({
        message: "No files found!",
      });
    }
    const chunkCursor = await(chunks.find({files_id: cursor[cursor.length-1]._id}).toArray());
    return res.status(200).send(chunkCursor[0].data);
  } catch (error) {
    return res.status(500).send({
      message: error.message,
    });
  }
};

const deleteFile = async (req, res) => {
  try {
    await mongoClient.connect();
    const database = mongoClient.db(dbConfig.database);
    const images = database.collection(dbConfig.imgBucket + ".files");
    const chunks = database.collection(dbConfig.imgBucket + ".chunks");
    const cursor = await (images.find({filename: req.body.name}).toArray());
    if (cursor.length > 0) {
      await chunks.deleteMany({files_id: cursor[cursor.length-1]._id});
      await images.deleteMany({filename: req.body.name});
    }
    return res.status(200).send({ message: 'Delete Image Succeed'});
  } catch (error) {
    return res.status(500).send({
      message: error.message,
    });
  }
};

const uploadPhysicalFile = async (req, res) => {
  try {
    // Destination and file name would be adjusted to be the same with original file system
    const {objectId, name, fileType, model} = req.query;
    const uploadedFile = req.file;
    if (!uploadedFile) {
      return res.status(400).send({
        message: 'No file uploaded.'
      })
    }
    return res.status(200).send({
      message: `File ${fileType} Uploaded Successfully for ${model} ${objectId}-${name}`
    })
    
  } catch (error) {
    return res.status(500).send({
      message: error.message,
    });
  }
}

const deletePhysicalFile = async (req, res) => {
  try {
    const { objectId, fileType, model, fileName } = req.body || {};
    if (!objectId || !fileType || !model || !fileName) {
      return res.status(400).send({ message: 'Required fields missed' });
    }

    const BASE_UPLOAD_DIR = `/www/wwwroot/upload/`;
    const targetFilePath = path.join(BASE_UPLOAD_DIR, model, objectId, fileType, fileName);

    if (!fs.existsSync(targetFilePath)) {
      return res.status(200).send({ message: 'File already removed.' });
    }

    await fs.promises.unlink(targetFilePath);
    return res.status(200).send({ message: 'File deleted successfully.' });
  } catch (error) {
    return res.status(500).send({
      message: error.message,
    });
  }
}

const getFilesByType = async (req, res) => {
  try {
    const {objectId, fileType, name, model} = req.params;

    if (!objectId || !name || !fileType || !model) {
      return res.status(400).send({message: 'Required fields missed'});
    }

    const BASE_UPLOAD_DIR = `/www/wwwroot/upload/`; 
    const filesDir = `${BASE_UPLOAD_DIR}${model}/${objectId}/${fileType}/`;

    if (!fs.existsSync(filesDir)) {
      return res.status(200).send({
        data: {
          objectId,
          model,
          fileType,
          name,
          files: [],
          count: 0
        }
      })
    }

    const fileEntries = await readdir(filesDir, { withFileTypes: true});

    const filePromises = fileEntries.filter(entry => entry.isFile()).map(async (entry) => {
      const filePath = path.join(filesDir, entry.name);
      const stats = await stat(filePath);

      const fileUrl = `/files/${model}/${objectId}/${fileType}/${entry.name}`;
      return {
        name: entry.name,
        url: fileUrl,
        size: stats.size,
        extension: path.extname(entry.name),
        createdAt: stats.birthtime,
        modifiedAt: stats.mtime
      }
    });
    const files = await Promise.all(filePromises);
    return res.status(200).json({
      data: {
        objectId,
        fileType,
        name,
        files,
        count: files.length
      }
    })

  } catch(err) {
    return res.status(500).send({
      message: err.message
    })
  }
}



module.exports = {
  uploadFiles,
  getFile,
  deleteFile,
  uploadPhysicalFile,
  deletePhysicalFile,
  getFilesByType
};