"use strict";

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

var Storage = require("@google-cloud/storage");
var crc32 = require("fast-crc32c");

function getGCS(options) {
  var storage = new Storage({
    keyFilename: options.keyFilename
  });
  return new GcsWrapper(storage);
}

var GcsWrapper = function GcsWrapper(storage) {
  _classCallCheck(this, GcsWrapper);

  this.storage = storage;
  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.storage.createBucket(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"
        });
      });
    }

    var bucket = self.storage.bucket(name);

    return new Promise(function(resolve, reject) {
      bucket.delete(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 bucket = self.storage.bucket(bucketName);

    return new Promise(function(resolve, reject) {
      bucket.upload(filePath, function(err, file, apiResponse) {
        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, saveToPath) {
    if (!bucketName || !filename || !saveToPath) {
      return new Promise(function(resolve, reject) {
        reject({
          status: 400,
          message: "Invalid parameters"
        });
      });
    }

    var bucket = self.storage.bucket(bucketName);
    var file = bucket.file(filename);

    return new Promise(function(resolve, reject) {
      file.download({ destination: saveToPath }, function(
        err,
        result,
        response
      ) {
        if (!err) {
          resolve({
            status: 200,
            message:
              'File "' +
              filename +
              '" was downloaded successfully from bucket "' +
              bucketName +
              '"'
          });
        } else {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
    });
  };

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

    var bucket = self.storage.bucket(bucketName);
    var file = bucket.file(filename);

    return new Promise(function(resolve, reject) {
      var stringifiedObject = JSON.stringify(object);
      file.save(stringifiedObject, function(err, data) {
        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) {
      var bucket = self.storage.bucket(bucketName, function(err) {
        if (err) {
          reject({
            status: 400,
            message: err.message
          });
        }
      });

      bucket.getFiles(function(err, data) {
        if (!err) {
          var objects = [];
          data.forEach(function(element) {
            objects.push({
              filename: element.id
            });
          });
          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) {
      var bucket = self.storage.bucket(bucketName, function(err) {
        if (err) {
          reject({
            status: 400,
            message: err.message
          });
        }
      });

      var file = bucket.file(filename, function(err) {
        if (err) {
          reject({
            status: 400,
            message: err.message
          });
        }
      });

      file.delete(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 bucket = self.storage.bucket(bucketName, function(err) {
        if (err) {
          reject({
            status: 400,
            message: err.message
          });
        }
      });
      var file = bucket.file(filename, function(err) {
        if (err) {
          reject({
            status: 400,
            message: err.message
          });
        }
      });

      file
        .createReadStream()
        .on("error", function(err) {
          reject({
            status: 400,
            message: err.message
          });
        })
        .on("response", function(response) {
          // Server connected and responded with the specified status and headers.
        })
        .on("data", function(data) {
          objectData = data;
        })
        .on("end", function() {
          resolve({
            status: 200,
            data: JSON.parse(objectData.toString("utf8")),
            message:
              'Object "' +
              filename +
              '" was fetched successfully from bucket "' +
              bucketName +
              '"'
          });
        });
    });
  };
};

module.exports = {
  getGCS: getGCS
};
