"use strict";

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

var fs = require("fs");
var pkgcloud = require("pkgcloud");
var Readable = require("stream").Readable;
var crc32 = require("fast-crc32c");
var path = require("path");

function getRACKSPACE(options) {
  var rackspace = pkgcloud.storage.createClient({
    provider: "rackspace",
    username: options.username,
    apiKey: options.apiKey,
    region: options.region || "IAD"
  });
  return new RackspaceWrapper(rackspace);
}

var RackspaceWrapper = function RackspaceWrapper(rackspace) {
  _classCallCheck(this, RackspaceWrapper);

  this.rackspace = rackspace;
  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.rackspace.createContainer(
        {
          name: 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.rackspace.destroyContainer(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"
        });
      });
    }

    var filename = path.basename(filePath);
    var params = {
      container: bucketName,
      remote: filename
    };

    return new Promise(function(resolve, reject) {
      var source = fs.createReadStream(filePath);
      var dest = self.rackspace.upload(params);

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

      dest.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"
        });
      });
    }
    var params = {
      container: bucketName,
      remote: filename
    };
    var dest = fs.createWriteStream(saveToPath);

    return new Promise(function(resolve, reject) {
      var source = self.rackspace.download(params);

      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 stream = new Readable();
      var stringifiedObject = JSON.stringify(object);
      stream.push(stringifiedObject);
      stream.push(null);

      // create a writeable stream for our destination
      var dest = self.rackspace.upload({
        container: bucketName,
        remote: filename
      });

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

      dest.on("success", function(file) {
        // 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'
            });
          }
        });
      });

      // pipe the source to the destination
      stream.pipe(dest);
    });
  };

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

    return new Promise(function(resolve, reject) {
      self.rackspace.getFiles(bucketName, function(err, data) {
        if (!err) {
          var objects = [];
          data.forEach(function(element) {
            objects.push({
              filename: element.name
            });
          });
          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) {
      self.rackspace.removeFile(bucketName, filename, 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 objectData = void 0;
    return new Promise(function(resolve, reject) {
      var source = self.rackspace.download(
        {
          container: bucketName,
          remote: filename
        },
        function(err, data) {
          if (err) {
            reject({
              status: 400,
              message: err.message
            });
          }
        }
      );

      source.on("data", function(data) {
        objectData = data;
      });
      source.on("end", function() {
        resolve({
          status: 200,
          data: JSON.parse(objectData.toString("utf8")),
          message:
            'Object "' +
            filename +
            '" was fetched successfully from bucket "' +
            bucketName +
            '"'
        });
      });
    });
  };
};

module.exports = {
  getRACKSPACE: getRACKSPACE
};
