"use strict";

var fs = require("fs");
var path = require("path");
var crc32 = require("fast-crc32c");

function getRootFolder(options) {
  var folderPath = options.folderPath;
  return new FolderWrapper(folderPath);
}

function FolderWrapper(folderPath) {
  var rootFolder = folderPath;
  var self = this;

  self.createBucket = function(name) {
    if (!name) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      fs.mkdir(path.join(rootFolder, name), function(err) {
        if (!err) {
          resolve({
            status: 201,
            message: 'Bucket "' + name + '" was created successfully'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };

  self.deleteBucket = function(name) {
    if (!name) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      fs.rmdir(path.join(rootFolder, name), function(err) {
        if (!err) {
          resolve({
            status: 200,
            message: 'Bucket "' + name + '" was deleted successfully'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };

  self.uploadFile = function(bucketName, filePath) {
    if (!bucketName || !filePath) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      var filename = path.basename(filePath);
      var source = fs.createReadStream(filePath);
      var dest = fs.createWriteStream(
        path.join(rootFolder, bucketName, filename)
      );

      source.on("error", function(err) {
        reject({
          status: 400,
          message: err.message
        });
      });

      source.on("end", function() {
        resolve({
          status: 200,
          message:
            'File "' +
            filePath +
            '" was uploaded successfully to bucket "' +
            bucketName +
            '"'
        });
      });

      source.pipe(dest);
    });
  };

  self.downloadFile = function(bucketName, filename, saveToPath) {
    if (!bucketName || !filename || !saveToPath) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }
    return new Promise(function(resolve, reject) {
      var source = fs.createReadStream(
        path.join(rootFolder, bucketName, filename)
      );
      var dest = fs.createWriteStream(saveToPath);

      source.on("error", function(err) {
        reject({
          status: 400,
          message: err.message
        });
      });

      source.on("end", function() {
        resolve({
          status: 200,
          message:
            'File "' +
            filename +
            '" was downloaded successfully from bucket "' +
            bucketName +
            '"'
        });
      });

      source.pipe(dest);
    });
  };

  self.createFileFromText = function(bucketName, filename, object) {
    var shouldSimulateFileCorruption =
      arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;

    if (!bucketName || !filename || !object) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      var stringifiedObject = JSON.stringify(object);
      fs.writeFile(
        path.join(rootFolder, bucketName, filename),
        stringifiedObject,
        function(err) {
          if (!err) {
            // Check whether file was properly uploaded
            var localFileCrc32 = crc32.calculate(stringifiedObject);
            self.readFile(bucketName, filename).then(function(response) {
              var remoteFileCrc32 = void 0;
              var data = JSON.stringify(response.data);
              if (shouldSimulateFileCorruption) {
                data += "corrupted-sufix";
              }
              remoteFileCrc32 = crc32.calculate(data);

              if (localFileCrc32 === remoteFileCrc32) {
                resolve({
                  status: 200,
                  message:
                    'Object "' +
                    filename +
                    '" was saved successfully in bucket "' +
                    bucketName +
                    '"'
                });
              } else {
                reject({
                  status: 400,
                  message:
                    'CRC32 validation error. Object "' +
                    filename +
                    '" could not be uploaded successfully'
                });
              }
            });
          } else {
            reject({
              status: 400,
              message: err.message
            });
          }
        }
      );
    });
  };

  self.getListOfFiles = function(bucketName) {
    if (!bucketName) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      fs.readdir(path.join(rootFolder, bucketName), function(err, data) {
        if (!err) {
          var objects = [];
          data.forEach(function(element) {
            objects.push({
              filename: element
            });
          });
          resolve({
            status: 200,
            data: objects,
            message:
              'The list of objects was fetched successfully from bucket "' +
              bucketName +
              '"'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };

  self.deleteFile = function(bucketName, filename) {
    if (!bucketName || !filename) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      fs.unlink(path.join(rootFolder, bucketName, filename), function(err) {
        if (!err) {
          resolve({
            status: 200,
            message:
              'Object "' +
              filename +
              '" was deleted successfully from bucket "' +
              bucketName +
              '"'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };

  self.readFile = function(bucketName, filename) {
    if (!bucketName || !filename) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    return new Promise(function(resolve, reject) {
      fs.readFile(path.join(rootFolder, bucketName, filename), "utf8", function(
        err,
        object
      ) {
        if (!err) {
          resolve({
            status: 200,
            data: JSON.parse(object),
            message:
              'Object "' +
              filename +
              '" was fetched successfully from bucket "' +
              bucketName +
              '"'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };
}
module.exports = {
  getRootFolder: getRootFolder
};
