(function() {
  var Project, Promise, _, api, chalk, ciProvider, errors, git, headless, logException, logger, os, stdout, terminal, upload;

  _ = require("lodash");

  os = require("os");

  chalk = require("chalk");

  Promise = require("bluebird");

  headless = require("./headless");

  api = require("../api");

  logger = require("../logger");

  errors = require("../errors");

  stdout = require("../stdout");

  upload = require("../upload");

  Project = require("../project");

  git = require("../util/git");

  terminal = require("../util/terminal");

  ciProvider = require("../util/ci_provider");

  logException = function(err) {
    return logger.createException(err).timeout(1000)["catch"](function() {});
  };

  module.exports = {
    getBranch: function(repo) {
      var b, branch, i, len, ref;
      ref = ["CIRCLE_BRANCH", "TRAVIS_BRANCH", "CI_BRANCH"];
      for (i = 0, len = ref.length; i < len; i++) {
        branch = ref[i];
        if (b = process.env[branch]) {
          return Promise.resolve(b);
        }
      }
      return repo.getBranch();
    },
    generateProjectBuildId: function(projectId, projectPath, projectName, recordKey, group, groupId) {
      var repo;
      if (!recordKey) {
        errors["throw"]("RECORD_KEY_MISSING");
      }
      repo = git.init(projectPath);
      return Promise.props({
        sha: repo.getSha(),
        email: repo.getEmail(),
        author: repo.getAuthor(),
        remote: repo.getRemoteOrigin(),
        branch: this.getBranch(repo),
        message: repo.getMessage()
      }).then(function(git) {
        if (group) {
          if (groupId == null) {
            groupId = ciProvider.groupId();
          }
        } else {
          groupId = null;
        }
        return api.createRun({
          projectId: projectId,
          recordKey: recordKey,
          commitSha: git.sha,
          commitBranch: git.branch,
          commitAuthorName: git.author,
          commitAuthorEmail: git.email,
          commitMessage: git.message,
          remoteOrigin: git.remote,
          ciParams: ciProvider.params(),
          ciProvider: ciProvider.name(),
          ciBuildNumber: ciProvider.buildNum(),
          groupId: groupId
        })["catch"](function(err) {
          switch (err.statusCode) {
            case 401:
              recordKey = recordKey.slice(0, 5) + "..." + recordKey.slice(-5);
              return errors["throw"]("RECORD_KEY_NOT_VALID", recordKey, projectId);
            case 404:
              return errors["throw"]("DASHBOARD_PROJECT_NOT_FOUND", projectId);
            default:
              errors.warning("DASHBOARD_CANNOT_CREATE_RUN_OR_INSTANCE", err);
              return logException(err)["return"](null);
          }
        });
      });
    },
    createInstance: function(buildId, spec) {
      return api.createInstance({
        buildId: buildId,
        spec: spec
      })["catch"](function(err) {
        errors.warning("DASHBOARD_CANNOT_CREATE_RUN_OR_INSTANCE", err);
        if (err.statusCode !== 503) {
          return logException(err)["return"](null);
        } else {
          return null;
        }
      });
    },
    upload: function(options) {
      var count, nums, screenshotUrls, screenshots, send, uploads, video, videoUrl;
      if (options == null) {
        options = {};
      }
      video = options.video, screenshots = options.screenshots, videoUrl = options.videoUrl, screenshotUrls = options.screenshotUrls;
      uploads = [];
      count = 0;
      nums = function() {
        count += 1;
        return chalk.gray("(" + count + "/" + uploads.length + ")");
      };
      send = function(pathToFile, url) {
        var fail, success;
        success = function() {
          return console.log("  - Done Uploading " + (nums()), chalk.blue(pathToFile));
        };
        fail = function(err) {
          return console.log("  - Failed Uploading " + (nums()), chalk.red(pathToFile));
        };
        return uploads.push(upload(pathToFile, url).then(success)["catch"](fail));
      };
      if (videoUrl) {
        send(video, videoUrl);
      }
      if (screenshotUrls) {
        screenshotUrls.forEach(function(obj) {
          var screenshot;
          screenshot = _.find(screenshots, {
            clientId: obj.clientId
          });
          return send(screenshot.path, obj.uploadUrl);
        });
      }
      if (!uploads.length) {
        console.log("  - Nothing to Upload");
      }
      return Promise.all(uploads)["catch"](function(err) {
        errors.warning("DASHBOARD_CANNOT_UPLOAD_RESULTS", err);
        return logException(err);
      });
    },
    uploadAssets: function(instanceId, stats, stdout) {
      var screenshots;
      console.log("");
      console.log("");
      terminal.header("Uploading Assets", {
        color: ["blue"]
      });
      console.log("");
      screenshots = _.map(stats.screenshots, function(screenshot) {
        return _.omit(screenshot, "path");
      });
      return api.updateInstance({
        instanceId: instanceId,
        tests: stats.tests,
        passes: stats.passes,
        failures: stats.failures,
        pending: stats.pending,
        duration: stats.duration,
        error: stats.error,
        video: !!stats.video,
        screenshots: screenshots,
        failingTests: stats.failingTests,
        cypressConfig: stats.config,
        ciProvider: ciProvider.name(),
        stdout: stdout
      }).then((function(_this) {
        return function(resp) {
          if (resp == null) {
            resp = {};
          }
          return _this.upload({
            video: stats.video,
            screenshots: stats.screenshots,
            videoUrl: resp.videoUploadUrl,
            screenshotUrls: resp.screenshotUploadUrls
          });
        };
      })(this))["catch"](function(err) {
        errors.warning("DASHBOARD_CANNOT_CREATE_RUN_OR_INSTANCE", err);
        if (err.statusCode !== 503) {
          return logException(err)["return"](null);
        } else {
          return null;
        }
      });
    },
    uploadStdout: function(instanceId, stdout) {
      return api.updateInstanceStdout({
        instanceId: instanceId,
        stdout: stdout
      })["catch"](function(err) {
        errors.warning("DASHBOARD_CANNOT_CREATE_RUN_OR_INSTANCE", err);
        if (err.statusCode !== 503) {
          return logException(err);
        }
      });
    },
    run: function(options) {
      var captured, projectPath, type;
      projectPath = options.projectPath;
      captured = stdout.capture();
      if (options.ci) {
        type = (function() {
          switch (false) {
            case !process.env.CYPRESS_CI_KEY:
              return "CYPRESS_CI_DEPRECATED_ENV_VAR";
            default:
              return "CYPRESS_CI_DEPRECATED";
          }
        })();
        errors.warning(type);
      }
      return Project.add(projectPath).then(function() {
        return Project.id(projectPath)["catch"](function() {
          return errors["throw"]("CANNOT_RECORD_NO_PROJECT_ID");
        });
      }).then((function(_this) {
        return function(projectId) {
          options.projectId = projectId;
          return Project.config(projectPath).then(function(cfg) {
            var projectName;
            projectName = cfg.projectName;
            return _this.generateProjectBuildId(projectId, projectPath, projectName, options.key, options.group, options.groupId).then(function(buildId) {
              if (!buildId) {
                return;
              }
              return _this.createInstance(buildId, options.spec);
            }).then(function(instanceId) {
              var didUploadAssets;
              options.ensureAuthToken = false;
              options.allDone = false;
              didUploadAssets = false;
              return headless.run(options).then(function(stats) {
                if (stats == null) {
                  stats = {};
                }
                if (instanceId) {
                  return _this.uploadAssets(instanceId, stats, captured.toString()).then(function(ret) {
                    return didUploadAssets = ret !== null;
                  })["return"](stats)["finally"](function() {
                    headless.allDone();
                    if (didUploadAssets) {
                      stdout.restore();
                      return _this.uploadStdout(instanceId, captured.toString());
                    }
                  });
                } else {
                  stdout.restore();
                  headless.allDone();
                  return stats;
                }
              });
            });
          });
        };
      })(this));
    }
  };

}).call(this);
