import fs from 'fs'
import path from 'path'
import * as archiver from 'archiver'
import request from 'superagent'
import { ProxyAgent } from 'proxy-agent';

export default class SaucelabsService {

  constructor() {
    this.fs = fs;
    this.path = path;
    this.archiver = archiver;
    this.request = request;
    if (process.env.http_proxy) {
      this.proxy = process.env.http_proxy;
      this.proxyA = new ProxyAgent();
    }
  }

  async getHar(sessionId, file) {
    console.log("retrieving network for session " + sessionId);

    let user = process.env.SAUCE_USERNAME;
    let key = process.env.SAUCE_ACCESS_KEY;
    let host = process.env.SAUCE_API_HOST;

    let timestamp = Date.now();
    let tmpFileName = timestamp + '_saucelabs_network.har';
    let tmpFilePath = this.path.join('.tmp', tmpFileName)

    let stream = this.fs.createWriteStream(tmpFilePath);

    try {
      if (this.proxy) {
        this.request
          .get('https://api.' + host + '/v1/eds/' + sessionId + '/network.har')
          .auth(user, key)
          .agent(this.proxyA)
          .buffer(true)
          .pipe(stream);
      } else {
        this.request
          .get('https://api.' + host + '/v1/eds/' + sessionId + '/network.har')
          .auth(user, key)
          .buffer(true)
          .pipe(stream);
      }

      let read_end = new Promise((resolve, reject) => {
        stream.on('error', err => reject(err));
        stream.on('finish', () => resolve());
        setTimeout(() => resolve(new Error('Error SaucelabsService getHar: Saucelabs network HAR download timed out after 2 minutes')), 120000);
      });

      let read_res = await read_end;

      if (read_res instanceof Error) {
        console.error(read_res.message);
        this.fs.writeFileSync(tmpFilePath, read_res.message, { flags: 'w' })
      } else {
        stream.close();
        console.log("network har was retrieved, Writing to file " + file);
        let archive_output = this.fs.createWriteStream(file);
        let archive = this.archiver('zip', {
          zlib: { level: 9 }
        });
        archive.on('warning', function (err) {
          throw err;
        });

        // good practice to catch this error explicitly
        archive.on('error', function (err) {
          throw err;
        });

        archive.pipe(archive_output);

        archive.file(tmpFilePath, { name: tmpFileName });
        archive.finalize();

        let write_end = new Promise((resolve, reject) => {
          archive_output.on('error', err => reject(err));
          archive_output.on('finish', () => resolve());
          setTimeout(() => resolve(new Error('Error SaucelabsService getHar: Saucelabs network HAR write to zip timed out after 1 minute')), 60000);
        });

        let write_res = await write_end;
        if (write_res instanceof Error) {
          console.error(write_res.message);
          this.fs.writeFileSync(file, write_res.message, { flags: 'w' })
        }

      }
      return true;
    } catch (error) {
      throw new Error('Error SaucelabsService getHar: ' + error)
    }
  }
}
