const archiver = require('archiver');
const fs = require('fs');
const AWS = require('aws-sdk');
const mime = require('mime');

const { version } = require('../package.json');
const VERSION_FILE_NAME = `build_v${version}.zip`;
const EB_S3_BUCKET = 'elasticbeanstalk___BUCKET_NAME';
const EB_APP_NAME = 'APPLICATION_NAME';
const EB_VERSION_LABEL = `api_v${version}_${Math.floor(Date.now() /1000)}`;
const EN_ENV_NAME = 'ENVIRONMENT_NAAME';

let progressOutputText = '';
let throttleProgressOutput = '';
const startProgressOutput = () => {
  throttleProgressOutput = setInterval(() => {
    console.log(progressOutputText);
  }, 2000);
};

const createApiZip = (apiPath) => {
  return new Promise((resolve) => {
    const deployZipFile = `${apiPath}/builds/${VERSION_FILE_NAME}`;

    if (fs.existsSync(deployZipFile)) {
      fs.unlinkSync(deployZipFile);
    }

    const output = fs.createWriteStream(deployZipFile);
    const archive = archiver('zip', {
      zlib: { level: 3 }, // Sets the compression level.
    });

    // =========== ElasticBenstalk  =====================================================================//
    archive.directory(apiPath + '/.platform', '.platform');

    // ======================== APPLICATION CODE COPY ===============================================//
    archive.directory(apiPath + '/data', 'data');
    archive.directory(apiPath + '/fixtures', 'fixtures');
    archive.directory(apiPath + '/module', 'module');
    archive.directory(apiPath + '/public', 'public');
    archive.directory(apiPath + '/templates', 'templates');
    archive.directory(apiPath + '/vendor', 'vendor');

    archive.on('progress', function (obj) {
      progressOutputText = 'Zipping...' + obj.entries.processed + ' - ' + obj.fs.processedBytes;
    });

    output.on('close', function () {
      console.log(archive.pointer() + ' total bytes');
      console.log('Zip to deploy is ready.');
      clearInterval(throttleProgressOutput);
      resolve(deployZipFile);
    });
    archive.on('warning', function (err) {
      if (err.code === 'ENOENT') {
        // log warning
      } else {
        // throw error
        throw err;
      }
    });
    archive.on('error', function (err) {
      throw err;
    });
    archive.pipe(output);
    archive.finalize();
    startProgressOutput();
  });
};

const updateEbEnvironment = (envName, versionLabel) => {
  return new Promise((resolve) => {
    AWS.config.loadFromPath('./ci/aws_key_eb_api_deploy.json');
    const elasticbeanstalk = new AWS.ElasticBeanstalk();

    const params = {
      EnvironmentName: envName,
      VersionLabel: versionLabel,
    };
    elasticbeanstalk.updateEnvironment(params, (err, data) => {
      if (err) {
        resolve(err);
        console.log(err);
      } else {
        resolve();
        console.log(`EB Environment update started. Application will be live in a short`);
      }
    });
  });
};
const createAppVersionOnElastichBeanstalk = (appName, s3Bucket, fileNameInBucket, versionLabel) => {
  return new Promise((resolve, reject) => {
    AWS.config.loadFromPath('./ci/aws_key_eb_api_deploy.json');
    const elasticbeanstalk = new AWS.ElasticBeanstalk();

    const params = {
      ApplicationName: appName,
      AutoCreateApplication: true,
      Description: 'uploaded from deploy_api script',
      Process: true,
      SourceBundle: {
        S3Bucket: s3Bucket,
        S3Key: fileNameInBucket,
      },
      VersionLabel: versionLabel,
    };


    elasticbeanstalk.createApplicationVersion(params, (err, data) => {
      if (err) {
        reject(err);
        console.log(err);
      } else {
        resolve();
        console.log(`Application version created`);
      }
    });
  });
};

const uploadFileOnS3 = (filePath, bucketName, fileToCopy) => {
  return new Promise((resolve) => {
    AWS.config.loadFromPath('./ci/aws_key_eb_api_deploy.json');
    const s3 = new AWS.S3();

    const params = {
      Bucket: bucketName,
      Key: fileToCopy,
      Body: fs.readFileSync(filePath),
      ContentType: mime.getType(filePath),
      ACL: 'public-read',
    };

    s3.putObject(params, (err, data) => {
      if (err) {
        resolve(err);
        console.log(err);
      } else {
        resolve();
        console.log(`File ${fileToCopy} copied to root`);
      }
    });
  });
};

const start = async () => {
  const apiPath = __dirname + '/../api';
  console.log('Zipping PHP app: ' + apiPath);
  const deployZipFile = await createApiZip(apiPath);
  if (fs.existsSync(deployZipFile)) {

    console.log('Uploading on S3: ' + deployZipFile);
    await uploadFileOnS3(deployZipFile, EB_S3_BUCKET, VERSION_FILE_NAME);

    console.log('Set version on EB');
    await createAppVersionOnElastichBeanstalk(EB_APP_NAME, EB_S3_BUCKET, VERSION_FILE_NAME, EB_VERSION_LABEL);

    console.log('Activate version on EB');
    await updateEbEnvironment(EN_ENV_NAME, EB_VERSION_LABEL);
  }
};

start();