"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

function _defineProperty2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

  _defineProperty2 = function () {
    return data;
  };

  return data;
}

function _serializeError() {
  const data = _interopRequireDefault(require("serialize-error"));

  _serializeError = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _objectHash() {
  const data = _interopRequireDefault(require("object-hash"));

  _objectHash = function () {
    return data;
  };

  return data;
}

function _uniqid() {
  const data = _interopRequireDefault(require("uniqid"));

  _uniqid = function () {
    return data;
  };

  return data;
}

function _yn() {
  const data = _interopRequireDefault(require("yn"));

  _yn = function () {
    return data;
  };

  return data;
}

function _ramda() {
  const data = _interopRequireDefault(require("ramda"));

  _ramda = function () {
    return data;
  };

  return data;
}

function _os() {
  const data = _interopRequireDefault(require("os"));

  _os = function () {
    return data;
  };

  return data;
}

function _child_process() {
  const data = require("child_process");

  _child_process = function () {
    return data;
  };

  return data;
}

function _globalConfig() {
  const data = require("../api/consumer/lib/global-config");

  _globalConfig = function () {
    return data;
  };

  return data;
}

function _prompts() {
  const data = require("../prompts");

  _prompts = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../constants");

  _constants = function () {
    return data;
  };

  return data;
}

const LEVEL = {
  DEBUG: 'debug',
  INFO: 'info',
  WARNING: 'warning',
  ERROR: 'error',
  FATAL: 'fatal'
};

class Breadcrumb {
  constructor(category, message, data) {
    this.category = category;
    this.message = message;
    this.data = data;
  }

}

class Analytics {
  static getID() {
    const id = (0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_USERID_KEY);
    if (id) return id;
    const newId = (0, _uniqid().default)();
    (0, _globalConfig().setSync)(_constants().CFG_ANALYTICS_USERID_KEY, newId);
    return newId;
  }

  static promptAnalyticsIfNeeded(cmd) {
    function shouldPromptForAnalytics() {
      // do not prompt analytics approval for bit config command (so you can configure it in CI envs)
      if (cmd.length && cmd[0] !== 'config') {
        const analyticsReporting = (0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_REPORTING_KEY);
        const errorReporting = (0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_ERROR_REPORTS_KEY);
        return _ramda().default.isNil(analyticsReporting) && _ramda().default.isNil(errorReporting);
      }

      return false;
    }

    if (shouldPromptForAnalytics()) {
      const uniqId = (0, _uniqid().default)();
      if (!(0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_USERID_KEY)) (0, _globalConfig().setSync)(_constants().CFG_ANALYTICS_USERID_KEY, uniqId);
      return (0, _prompts().analyticsPrompt)().then(({
        analyticsResponse
      }) => {
        (0, _globalConfig().setSync)(_constants().CFG_ANALYTICS_REPORTING_KEY, (0, _yn().default)(analyticsResponse));

        if (!(0, _yn().default)(analyticsResponse)) {
          return (0, _prompts().errorReportingPrompt)().then(({
            errResponse
          }) => {
            return (0, _globalConfig().setSync)(_constants().CFG_ANALYTICS_ERROR_REPORTS_KEY, (0, _yn().default)(errResponse));
          });
        }

        return Promise.resolve();
      });
    }

    return Promise.resolve();
  }

  static _maskString(str) {
    return str.replace(/[A-Za-z]/g, 'x');
  }

  static _hashLightly(value) {
    switch (typeof value) {
      case 'undefined':
      case 'number':
      case 'boolean':
        return value;

      case 'string':
        return this._maskString(value);

      case 'object':
        if (Array.isArray(value)) return value.map(item => this._hashLightly(item));
        if (value === null) return value;
        return (0, _objectHash().default)(value);

      default:
        return (0, _objectHash().default)(value);
    }
  }

  static _hashFlags(flags) {
    const hashedFlags = {};

    const definedFlags = _ramda().default.filter(flag => typeof flag !== 'undefined', flags);

    if (this.anonymous && !_ramda().default.isEmpty(definedFlags)) {
      Object.keys(definedFlags).forEach(key => {
        hashedFlags[key] = this._hashLightly(flags[key]);
      });
      return hashedFlags;
    }

    return definedFlags;
  }

  static _hashArgs(args) {
    if (!this.anonymous) return args;
    return args.map(arg => this._hashLightly(arg));
  }

  static init(command, flags, args, version) {
    this.anonymous = (0, _yn().default)((0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_ANONYMOUS_KEY), {
      default: true
    });
    this.command = command;
    this.flags = this._hashFlags(flags);
    this.release = version;
    this.args = this._hashArgs(args);
    this.nodeVersion = process.version;
    this.os = process.platform;
    this.level = LEVEL.INFO;
    this.username = !this.anonymous ? (0, _globalConfig().getSync)(_constants().CFG_USER_EMAIL_KEY) || (0, _globalConfig().getSync)(_constants().CFG_USER_NAME_KEY) || _os().default.hostname() || this.getID() : this.getID();
    this.analytics_usage = (0, _yn().default)((0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_REPORTING_KEY), {
      default: false
    });
    this.error_usage = this.analytics_usage ? true : (0, _yn().default)((0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_ERROR_REPORTS_KEY), {
      default: false
    });
    this.environment = (0, _globalConfig().getSync)(_constants().CFG_ANALYTICS_ENVIRONMENT_KEY) || _constants().DEFAULT_BIT_ENV;
  }

  static sendData() {
    return new Promise((resolve, reject) => {
      if (this.analytics_usage || this.error_usage && !this.success) {
        const file = _path().default.join(__dirname, 'analytics-sender.js');

        const forked = (0, _child_process().fork)(file, {
          silent: true
        }); // switch to `false` to debug the child
        // console.log('sending', this.toObject()); // un-comment to see the data sent to Analytics

        forked.send(this.toObject());
        forked.on('message', () => {
          // makes sure the data has been sent to the child.
          // without it, when the message is large, it exits before the child got the complete message
          resolve();
        });
        forked.on('error', err => {
          reject(err);
        });
      } else {
        resolve();
      }
    });
  }

  static setError(level = LEVEL.ERROR, err) {
    this.level = level;
    this.error = (0, _serializeError().default)(err);
    this.success = false;
  }
  /**
   * eventually goes to the "ADDITIONAL DATA" section in Sentry
   */


  static setExtraData(key, value) {
    this.extra[key] = value;
  }

  static incExtraDataKey(key, value) {
    if (this.extra[key]) {
      this.extra[key] += value || 1;
    } else {
      this.extra[key] = value || 1;
    }
  }

  static hashData(data) {
    if (this.anonymous) {
      return (0, _objectHash().default)(data);
    }

    return data;
  }

  static addBreadCrumb(category, message, data) {
    this.breadcrumbs.push(new Breadcrumb(category, message, data));
  }

  static toObject() {
    return {
      username: this.username,
      command: this.command,
      flags: this.flags,
      args: this.args,
      release: this.release,
      extra: this.extra,
      nodeVersion: this.nodeVersion,
      os: this.os,
      level: this.level,
      error: this.error,
      success: this.success,
      breadcrumbs: this.breadcrumbs,
      analytics_usage: this.analytics_usage,
      error_usage: this.analytics_usage,
      environment: this.environment
    };
  }

}

(0, _defineProperty2().default)(Analytics, "flags", {});
(0, _defineProperty2().default)(Analytics, "success", true);
(0, _defineProperty2().default)(Analytics, "extra", {});
(0, _defineProperty2().default)(Analytics, "breadcrumbs", []);
module.exports = {
  LEVEL,
  Analytics
};