"use strict";

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

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

function getAWS(options) {
  var s3 = new AWS.S3({
    accessKeyId: options.accessKeyId,
    secretAccessKey: options.secretAccessKey,
    region: options.region || "us-east-1"
  });

  return new AwsWrapper(s3);
}

var AwsWrapper = function AwsWrapper(s3) {
  _classCallCheck(this, AwsWrapper);

  this.s3 = s3;
  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) {
      self.s3.createBucket({ Bucket: name }, function(err, data) {
        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) {
      self.s3.deleteBucket({ Bucket: name }, function(err, data) {
        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"
        });
      });
    }

    var params = {
      Bucket: bucketName,
      Key: path.basename(filePath),
      Body: fs.createReadStream(filePath)
    };
    var fileSize = fs.statSync(filePath);

    var preferredPartSize = (fileSize.size > 50000 ? 10 : 5) * 1024 * 1024;
    var options = {
      partSize: preferredPartSize,
      queueSize: 10
    };

    return new Promise(function(resolve, reject) {
      self.s3.upload(params, options, function(err, data) {
        if (!err) {
          resolve({
            status: 200,
            message:
              'File "' +
              filePath +
              '" was uploaded successfully to bucket "' +
              bucketName +
              '"'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };

  self.downloadFile = function(bucketName, filename, downloadedFilePath) {
    if (!bucketName || !filename || !downloadedFilePath) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }
    var params = {
      Bucket: bucketName,
      Key: filename
    };
    var file = fs.createWriteStream(downloadedFilePath);

    return new Promise(function(resolve, reject) {
      var source = self.s3.getObject(params).createReadStream();

      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(file);
    });
  };

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

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

    var params = {
      Bucket: bucketName,
      Key: filename,
      Body: JSON.stringify(content)
    };
    return new Promise(function(resolve, reject) {
      self.s3.putObject(params, function(err, data) {
        if (!err) {
          // Check whether file was properly uploaded
          var localFileCrc32 = crc32.calculate(params.Body);

          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"
        });
      });
    }

    var params = {
      Bucket: bucketName
    };
    return new Promise(function(resolve, reject) {
      self.s3.listObjectsV2(params, function(err, data) {
        if (!err) {
          var objects = [];
          data.Contents.forEach(function(element) {
            objects.push({
              filename: element.Key
            });
          });
          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"
        });
      });
    }

    var params = {
      Bucket: bucketName,
      Key: filename
    };

    return new Promise(function(resolve, reject) {
      self.s3.deleteObject(params, function(err, data) {
        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"
        });
      });
    }

    var params = {
      Bucket: bucketName,
      Key: filename
    };
    return new Promise(function(resolve, reject) {
      self.s3.getObject(params, function(err, data) {
        if (!err) {
          resolve({
            status: 200,
            data: JSON.parse(data.Body.toString("utf-8")),
            message:
              'Object "' +
              filename +
              '" was fetched successfully from bucket "' +
              bucketName +
              '"'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };
};

module.exports = {
  getAWS: getAWS,
  AwsWrapper: AwsWrapper
};
