// This script assumes the following:
//   1. You've installed wd with `npm install wd'.
//   2. You've set the environment variables $SAUCE_USERNAME and $SAUCE_ACCESS_KEY.
//   3. If the environment variable $CIRCLE_ARTIFACTS is not set images will be saved in /tmp
//
// This scripts creates following files for each browser in browserVersions:
//    $CIRCLE_ARTIFACTS/imgs/{browser_version_platform}/#.png
//
// The intention of this script is that it will be ran from CircleCI
//
// Example usage:
//   node screenshots.js http://localhost:9292/test/visual.html
//   node screenshots.js http://google.com

var wd = require('wd');
var fs = require('fs');
var url = process.argv[2];
var username = process.env.SAUCE_USERNAME;
var accessKey = process.env.SAUCE_ACCESS_KEY;
var build_name = process.env.MQ_CI_BUILD_NAME;
var baseDir = process.env.CIRCLE_ARTIFACTS;
if (!baseDir) {
  console.error('No $CIRCLE_ARTIFACTS found, for testing do something like `CIRCLE_ARTIFACTS=/tmp script/screenshots.js`');
  process.exit(1);
}
fs.mkdirSync(baseDir+'/imgs');
fs.mkdirSync(baseDir+'/imgs/pieces');
fs.mkdirSync(baseDir+'/browser_logs');

var browsers = [
  {
    config: {
      browserName: 'Internet Explorer',
      platform: 'Windows XP'
    },
    pinned: true // should be pinned to IE 8
  },
  {
    config: {
      // Expecting IE 11
      browserName: 'Internet Explorer',
      platform: 'Windows 7'
    },
    pinned: true // should be pinned to IE 11
  },
  {
    config: {
      browserName: 'MicrosoftEdge',
      platform: 'Windows 10'
    }
  },
  {
    config: {
      browserName: 'Firefox',
      platform: 'OS X 10.11'
    }
  },
  {
    config: {
      browserName: 'Safari',
      platform: 'OS X 10.11'
    }
  },
  {
    config: {
      browserName: 'Chrome',
      platform: 'OS X 10.11'
    }
  },
  {
    config: {
      browserName: 'Firefox',
      platform: 'Linux'
    }
  }
];


browsers.forEach(function(browser) {
  browser.config.build = build_name;
  browser.config.name = 'Visual tests, ' + browser.config.browserName + ' on ' + browser.config.platform;
  browser.config.customData = {build_url: process.env.CIRCLE_BUILD_URL};
  var browserDriver = wd.promiseChainRemote('ondemand.saucelabs.com', 80, username, accessKey);
  return browserDriver.init(browser.config)
  .then(function(args) {
    var cfg = browser.config, capabilities = args[1];
    var version = capabilities.version || capabilities.browserVersion;
    var sessionName = [cfg.browserName, version, cfg.platform].join(' ');
    if (capabilities.platformVersion) sessionName += ' ' + capabilities.platformVersion;
    console.log(sessionName, 'init', args);

    var evergreen = browser.pinned ? '' : '_(evergreen)';
    var fileName = [cfg.browserName, version + evergreen, cfg.platform].join('_');
    if (capabilities.platformVersion) fileName += ' ' + capabilities.platformVersion;
    fileName = fileName.replace(/ /g, '_');

    return browserDriver.get(url)
    .then(willLog(sessionName, 'get'))
    .safeExecute('document.body.focus()') // blur anything that's auto-focused
    .then(willLog(sessionName, 'document.body.focus()'))
    .safeExecute('document.documentElement.style.overflow = "hidden"') // hide scrollbars
    .then(willLog(sessionName, 'hide scrollbars'))
    .then(function() {
      // Microsoft Edge starts out with illegally big window: https://git.io/vD63O
      if (cfg.browserName === 'MicrosoftEdge') {
        return browserDriver.getWindowSize()
        .then(function(size) {
          return browserDriver.setWindowSize(size.width, size.height)
        })
        .then(willLog(sessionName, 'reset window size (Edge-only workaround)'))
      }
    })
    .then(function() {
      return [browserDriver.safeExecute('document.documentElement.scrollHeight'),
              browserDriver.safeExecute('document.documentElement.clientHeight')];
    })
    .spread(function(scrollHeight, viewportHeight) {
      console.log(sessionName, 'get scrollHeight, clientHeight', scrollHeight, viewportHeight);

      // the easy case: Firefox and IE return a screenshot of the entire webpage
      if (cfg.browserName === 'Firefox' || cfg.browserName === 'Internet Explorer') {
        return browserDriver.saveScreenshot(baseDir + '/imgs/' + fileName + '.png')
        .then(willLog(sessionName, 'saveScreenshot'))
      // the hard case: for Chrome, Safari, and Edge, scroll through the page and
      // take screenshots of each piece; circle.yml will stitch them together
      } else {
        var piecesDir = baseDir + '/imgs/pieces/' + fileName + '/';
        fs.mkdirSync(piecesDir);

        var scrollTop = 0;
        var index = 1;

        return (function loop() {
          return browserDriver.safeEval('window.scrollTo(0,'+scrollTop+');')
          .then(willLog(sessionName, 'scrollTo()'))
          .saveScreenshot(piecesDir + index + '.png')
          .then(function() {
            console.log(sessionName, 'saveScreenshot');

            scrollTop += viewportHeight;
            index += 1;

            // if the viewport hasn't passed the bottom edge of the page yet,
            // scroll down and take another screenshot
            if (scrollTop + viewportHeight <= scrollHeight) {
              // Use `window.scrollTo` because thats what jQuery does:
              //   https://github.com/jquery/jquery/blob/1.12.3/src/offset.js#L186
              // Use `window.scrollTo` instead of jQuery because jQuery was
              // causing a stackoverflow in Safari.
              return loop();
            } else { // we are past the bottom edge of the page, reduce window size to
              // fit only the part of the page that hasn't been screenshotted.

              // If there is no remaining part of the page, we're done, short-circuit
              if (scrollTop === scrollHeight) return browserDriver;

              return browserDriver.getWindowSize()
              .then(function(windowSize) {
                console.log(sessionName, 'getWindowSize');
                // window size is a little bigger than the viewport because of address
                // bar and scrollbars and stuff
                var windowPadding = windowSize.height - viewportHeight;
                var newWindowHeight = scrollHeight - scrollTop + windowPadding;
                return browserDriver.setWindowSize(windowSize.width, newWindowHeight)
                .then(willLog(sessionName, 'setWindowSize'))
                .safeEval('window.scrollTo(0,'+scrollHeight+');')
                .then(willLog(sessionName, 'scrollTo() Final'))
                .saveScreenshot(piecesDir + index + '.png')
                .then(willLog(sessionName, 'saveScreenshot Final'));
              });
            }
          });
        }());
      }
    })
    .then(function() {
      return browserDriver.log('browser')
      .then(function(logs) {
        var logfile = baseDir + '/browser_logs/' + sessionName.replace(/ /g, '_') + '.log';
        return new Promise(function(resolve, reject) {
          fs.writeFile(logfile, JSON.stringify(logs, null, 2), function(err) {
            err ? reject(err) : resolve();
          });
        })
        .then(willLog(sessionName, 'writeFile'));
      }, function(err) {
        // the Edge, IE, and Firefox-on-macOS drivers don't support logs, but the others do
        console.log(sessionName, 'Error fetching logs:', JSON.stringify(err, null, 2));
      });
    });
  })
  .sauceJobStatus(true)
  .fail(function(err) {
    console.log('ERROR:', browser.config.browserName, browser.config.platform);
    console.log(JSON.stringify(err, null, 2));
  })
  .quit();

  function willLog() {
    var msg = [].join.call(arguments, ' ');
    return function(value) {
      console.log(msg);
      return value;
    };
  }
});
