import path from 'path'
import S3 from 'aws-sdk/clients/s3.js';
import proxyAgent from 'proxy-agent';
import { createReadStream, readdir, stat } from 'fs';
import * as mime from 'node-mime-types';

export default class S3Service {
  // You need to set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables for this service to work

  constructor() {
      this.path = path;
      
      if (process.env.http_proxy){
        let proxy = proxyAgent;
        this.s3 = new S3({
          signatureVersion: 'v4',
          httpOptions: { agent: proxy(process.env.http_proxy) }
        });
      } else {
        this.s3 = new S3({
          signatureVersion: 'v4'
        });
      }

  }

  async uploadFile({ path, params, options } = {}) {
      const parameters = { ...params };
      if (!parameters.Bucket){
          throw new Error('S3-service; s3 bucket not defined in params');
      }
      const opts = { ...options };

      try {
          const readStream = createReadStream(this.path.resolve(path));

          readStream.once('error', (err) => {
            console.error(`unable to upload file ${path}, ${err.message}`);
          });

          parameters.Body = readStream;
          parameters.ContentType = mime.getMIMEType(path);

          await this.s3.upload(parameters, opts).promise();

          console.info(`${parameters.Key} uploaded in bucket ${parameters.Bucket}`);
        } catch (e) {
          throw new Error(`unable to upload file ${path} at ${parameters.Key}, ${e.message}`);
        }

      return true;
  }

  async  uploadDirectory({
      path,
      params,
      options,
      rootKey,
    } = {}) {
      //promises : {readdir, stat: getStats}
      const parameters = { ...params };
      if (!parameters.Bucket ) {
        throw new Error('S3-service; s3 bucket not defined in params');
      }
      const opts = { ...options };
      const root = rootKey && rootKey.constructor === String ? rootKey : '';

      let dirPath;

      try {
        dirPath = this.path.resolve(path);
        const dirStats = await getStats(dirPath);

        if (!dirStats.isDirectory()) {
          throw new Error(`${dirPath} is not a directory`);
        }

        const filenames = await readdir(dirPath);

        if (Array.isArray(filenames)) {
          await Promise.all(filenames.map(async (filename) => {
            const filepath = `${dirPath}/${filename}`;
            const fileStats = await getStats(filepath);

            if (fileStats.isFile()) {
              parameters.Key = root + '/' + filename;
              await this.uploadFile({
                path: filepath,
                params: parameters,
                options: opts
              });
            } else if (fileStats.isDirectory()) {
              await this.uploadDirectory({
                params,
                options,
                path: filepath,
                rootKey: root + '/' + filename,
              });
            }
          }));
        }
      } catch (e) {
        throw new Error(`unable to upload directory ${path}, ${e.message}`);
      }

      console.info(`directory ${dirPath} successfully uploaded`);
      return true;
    };
}
