'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _watchr = require('watchr');

var _watchr2 = _interopRequireDefault(_watchr);

var _chalk = require('chalk');

var _chalk2 = _interopRequireDefault(_chalk);

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _debug = require('../utils/debug');

var _debug2 = _interopRequireDefault(_debug);

var _spinner = require('./helpers/spinner');

var _socket = require('./helpers/socket');

var _printTools = require('../utils/print-tools');

var _dateUtils = require('../utils/date-utils');

var _print = require('./helpers/print');

var _socketTrace = require('./socket-trace');

var _socketTrace2 = _interopRequireDefault(_socketTrace);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new _bluebird2.default(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return _bluebird2.default.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

const { debug } = (0, _debug2.default)('cmd-socket-deploy');

const pendingUpdates = {};
const timer = new _dateUtils.Timer();

class SocketDeployCmd {
  constructor(context) {
    this.context = context;
    this.session = context.session;
    this.Socket = context.Socket;
    this.registry = new context.Registry();
    this.firstRun = true;

    this.mainSpinner = new _spinner.GlobalSpinner((0, _printTools.p)(3)(`${_chalk2.default.grey('waiting...')}`));
  }

  run([socketName, cmd]) {
    var _this = this;

    return _asyncToGenerator(function* () {
      _this.cmd = cmd;

      if (cmd.hot) {
        (0, _printTools.echo)(2)(`🔥 ${_chalk2.default.grey(' Hot deploy started')} ${_chalk2.default.dim('(Hit Ctrl-C to stop)')}`);
        (0, _printTools.echo)();
      }

      if (socketName) {
        debug(`Deploying Socket: ${socketName}`);
        const msg = (0, _printTools.p)(2)(`${_chalk2.default.magenta('getting sockets:')} ${(0, _dateUtils.currentTime)()}`);
        const spinner = new _spinner.SimpleSpinner(msg).start();
        _this.socketList = yield _this.Socket.flatList(socketName);
        const socket = _lodash2.default.find(_this.socketList, { name: socketName });
        spinner.stop();

        if (!(socket.existLocally || socket.isProjectRegistryDependency || socket.isDependencySocket)) {
          (0, _printTools.echo)();
          (0, _printTools.error)(4)(`Socket ${_chalk2.default.cyan(socketName)} cannot be found!`);
          (0, _printTools.echo)();
          process.exit(1);
        }
      } else {
        const msg = (0, _printTools.p)(2)(`${_chalk2.default.magenta('getting sockets:')} ${(0, _dateUtils.currentTime)()}`);
        const spinner = new _spinner.SimpleSpinner(msg).start();
        _this.socketList = yield _this.Socket.flatList();
        spinner.stop();
      }

      const configs = {};

      _bluebird2.default.each(_this.socketList, function (socketFromList) {
        return (0, _socket.askQuestions)(socketFromList.getConfigOptionsToAsk()).then(function (config) {
          configs[socketFromList.name] = config;
        });
      }).then(function () {
        return _this.deployProject();
      }).then(function (projectUpdateStatus) {
        return _bluebird2.default.all(_this.socketList.map(function (socket) {
          return _this.deploySocket(socket, configs[socket.name]);
        }));
      }).then(function () {
        if (cmd.hot) {
          debug('Starting stalker');
          _this.runStalker();
          _this.mainSpinner.queueSize += 1;
          _this.mainSpinner.queueSize += _this.socketList.length;
          _this.mainSpinner.start();

          if (cmd.trace) {
            const traces = new _socketTrace2.default(_this.context, _this.mainSpinner);
            _bluebird2.default.all(_this.socketList.map(function (socket) {
              return traces.startCollectingTraces(socket);
            }));
          }
        } else {
          (0, _printTools.echo)();
        }
      }).catch(function (err) {
        if (err.response && err.response.data && err.response.data.detail) {
          (0, _printTools.error)(4)(err.response.data.detail);
        } else {
          (0, _printTools.error)(4)(err);
        }
      });
    })();
  }
  deployProject() {
    var _this2 = this;

    return _asyncToGenerator(function* () {
      timer.reset();
      const msg = (0, _printTools.p)(4)(`${_chalk2.default.magenta('project deploy:')} ${(0, _dateUtils.currentTime)()}`);
      const spinner = new _spinner.SimpleSpinner(msg).start();
      return _this2.session.deployProject().then(function (deployProjectStatus) {
        spinner.stop();
        const status = _chalk2.default.grey('project synced:');
        const duration = timer.getDuration();
        (0, _printTools.echo)(5)(`${status} ${(0, _dateUtils.currentTime)()} ${duration}`);
      });
    })();
  }

  deploySocket(socket, config) {
    var _this3 = this;

    return _asyncToGenerator(function* () {
      const deployTimer = new _dateUtils.Timer();
      const msg = (0, _printTools.p)(4)(`${_chalk2.default.magenta('socket deploy:')} ${(0, _dateUtils.currentTime)()} ${_chalk2.default.cyan(socket.name)}`);
      const spinner = new _spinner.SimpleSpinner(msg).start();

      // We have co count here updates
      if (!pendingUpdates[socket.name]) {
        pendingUpdates[socket.name] = 0;
      }

      pendingUpdates[socket.name] += 1;
      if (pendingUpdates[socket.name] > 1) {
        spinner.stop();
        debug(`not updating, update pending: ${pendingUpdates[socket.name]}`);
        return;
      }

      const updateEnds = function () {
        // After update we have to understand if we should fire new one
        pendingUpdates[socket.name] -= 1;
        if (pendingUpdates[socket.name] > 0) {
          pendingUpdates[socket.name] = 0;
          _this3.deploySocket(socket, config);
        }
      };

      if (_this3.cmd.hot) {
        if (socket.shouldBeUpdated()) {
          return socket.update({ config }).then(function (updateStatus) {
            spinner.stop();
            SocketDeployCmd.printUpdateSuccessful(socket.name, updateStatus, deployTimer);
            updateEnds();
          }).catch(function (err) {
            if (typeof err === 'object') return (0, _printTools.error)('Socket sync failed!');
            spinner.stop();
            SocketDeployCmd.printUpdateFailed(socket.name, err, deployTimer);
            updateEnds();
          });
        }
        // Update is not necessery
        updateEnds();
        spinner.stop();
        SocketDeployCmd.printUpdateSuccessful(socket.name, { status: 'stopped' }, deployTimer);
        return _bluebird2.default.resolve();
      }

      // Let's compile and update if it is not hot mode
      return socket.compile().then(function (resp) {
        return socket.update({ config, withCompilation: true });
      }).then(function (updateStatus) {
        spinner.stop();
        SocketDeployCmd.printUpdateSuccessful(socket.name, updateStatus, deployTimer);
        if (updateStatus.status !== 0 && _this3.cmd.bail) {
          SocketDeployCmd.bail();
        }
      }).catch(function (err) {
        spinner.stop();
        (0, _print.printCompileError)(err, socket.name);

        if (_this3.cmd.bail) {
          SocketDeployCmd.bail();
        }
      });
    })();
  }

  getSocketToUpdate(fileName) {
    return this.localSockets.find(socket => socket.isSocketFile(fileName));
  }

  runStalker() {
    const resolveCallback = this.resolveCallback.bind(this);
    const rejectCallback = this.rejectCallback.bind(this);

    // Stalking files
    debug('watching:', this.session.projectPath);
    this.stalker = _watchr2.default.create(this.session.projectPath);
    this.stalker.on('change', (changeType, fileName) => {
      timer.reset();

      const socketToUpdate = this.getSocketToUpdate(fileName);
      if (!fileName.match(/\.js$/) && socketToUpdate) {
        // Search for which Socket was changed
        this.deploySocket(socketToUpdate);
      } else {
        this.mainSpinner.label(_chalk2.default.yellow((0, _printTools.p)(3)('changes detected...')));
      }
    });

    this.stalker.setConfig({
      interval: 300,
      persistent: true,
      catchupDelay: 300,
      preferredMethods: ['watch', 'watchFile'],
      followLinks: true,
      ignoreHiddenFiles: true, // ignoring .bundles, .dist etc.
      ignoreCommonPatterns: true
    });

    // First start of the stalker
    this.stalker.watch(() => {});

    this.localSockets = _lodash2.default.filter(this.socketList, { existLocally: true });
    this.mainSpinner.label(_chalk2.default.yellow((0, _printTools.p)(3)('starting compiler...')));
    const compiler = this.Socket.watchScripts(this.localSockets, resolveCallback, rejectCallback);
    if (!compiler) {
      console.log('WARN: nothing to watch!');
    }
  }

  resolveCallback(stats) {
    var _this4 = this;

    return _asyncToGenerator(function* () {
      _this4.mainSpinner.resetLabel();
      _this4.scriptWatch = true;
      timer.reset();

      if (!_this4.firstRun) {
        _bluebird2.default.all(_this4.localSockets.map(function (socket) {
          return _this4.deploySocket(socket);
        }));
      } else {
        _this4.mainSpinner.resetLabel();
      }
      _this4.firstRun = false;
    })();
  }

  rejectCallback(errObj) {
    this.mainSpinner.resetLabel();
    debug('rejectCallback');
    // if there is no endpoints watcher doesn't work
    if (errObj.errorType === 'noEndpointsError') {
      debug('nothing to watch, watcher is dead');
      this.scriptWatch = false;
    }
    this.mainSpinner.stop();
    (0, _print.printCompileError)(errObj);
    this.firstRun = false;
    this.mainSpinner.start();
  }

  static bail() {
    (0, _printTools.echo)();
    process.exit(1);
  }

  static printUpdateSuccessful(socketName, updateStatus, deployTimer) {
    debug('printUpdateSuccessful', socketName, updateStatus);
    const duration = _chalk2.default.dim(deployTimer.getDuration());
    const socketNameStr = `${_chalk2.default.cyan(socketName)}`;

    if (updateStatus.status === 'ok') {
      const status = _chalk2.default.grey('socket synced:');
      (0, _printTools.echo)(6)(`${status} ${(0, _dateUtils.currentTime)()} ${socketNameStr} ${duration}`);
    } else if (updateStatus.status === 'stopped') {
      // const status = format.grey('socket in sync:');
      // echo(5)(`${status} ${currentTime()} ${socketNameStr} ${duration}`);
    } else if (updateStatus.status === 'error') {
      const errDetail = _chalk2.default.red(updateStatus.message.error);
      const status = _chalk2.default.red('socket not synced:');
      (0, _printTools.echo)(2)(`${status} ${(0, _dateUtils.currentTime)()} ${socketNameStr} ${duration} ${errDetail}`);
    } else {
      const status = _chalk2.default.red('socket not synced:');
      (0, _printTools.echo)(2)(`${status} ${(0, _dateUtils.currentTime)()} ${socketNameStr} ${duration}`);
    }
  }

  static printUpdateFailed(socketName, err, deployTimer) {
    const duration = deployTimer.getDuration();
    const errDetail = JSON.parse(err).detail;
    (0, _printTools.echo)(3)(`${_chalk2.default.red('files not synced:')} ${(0, _dateUtils.currentTime)()} ${socketName} ${duration} ${errDetail}`);
  }
}
exports.default = SocketDeployCmd;
module.exports = exports['default'];
//# sourceMappingURL=socket-sync.js.map