"use strict";

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

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Mocker = void 0;

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

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

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

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

var _tsFns = require("ts-fns");

var _prototypes = require("../ty/prototypes.js");

var _type = require("../ty/type.js");

var _dict = require("../ty/dict.js");

var _list = require("../ty/list.js");

var _tuple = require("../ty/tuple.js");

var _enum = require("../ty/enum.js");

var _range = require("../ty/range.js");

var _mapping = require("../ty/mapping.js");

var _selfRef = require("../ty/self-ref.js");

var _rule = require("../ty/rule.js");

var Mocker = /*#__PURE__*/function () {
  function Mocker(loaders) {
    (0, _classCallCheck2.default)(this, Mocker);
    this.init(loaders);
  }

  (0, _createClass2.default)(Mocker, [{
    key: "init",
    value: function init() {
      var loaders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
      this.loaders = [].concat((0, _toConsumableArray2.default)(loaders), (0, _toConsumableArray2.default)(Mocker.defaultLoaders));
    }
  }, {
    key: "define",
    value: function define() {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      if (args.length === 2) {
        this.loaders.unshift(args);
      } else if (args.length === 1) {
        this.loaders.unshift(args[0]);
      }

      return this;
    }
  }, {
    key: "mock",
    value: function mock(type) {
      var _this = this;

      var count = 0;
      var asyncs = [];

      var makePath = function makePath(path, key) {
        return path ? path + '.' + key : key;
      };

      var makeEnum = function makeEnum(pattern, path) {
        var count = pattern.length;
        var index = parseInt(Math.random() * 10, 10) % count;
        var t = pattern[index];
        return createValue(t, path);
      };

      var makeObj = function makeObj(pattern, path) {
        var output = (0, _tsFns.map)(pattern, function (value, key) {
          var o = createValue(value, makePath(path, key));
          return o;
        });
        (0, _tsFns.each)(output, function (value, key) {
          if (value === '__SELF__') {
            delete output[key];
          }
        });
        return output;
      };

      var makeArr = function makeArr(pattern, path) {
        var output = [];
        var length = parseInt(Math.random() * 15, 10);

        for (var i = 0; i < length; i++) {
          output.push(makeEnum(pattern, makePath(path, i)));
        }

        var res = output.filter(function (item) {
          return item !== '__SELF__';
        });
        return res;
      };

      var createValue = function createValue(target) {
        var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';

        if ((0, _tsFns.isInstanceOf)(target, _type.Type)) {
          if ((0, _tsFns.isInstanceOf)(target, _selfRef.SelfRef)) {
            if (count > 10) {
              return '__SELF__';
            }

            target = target.pattern;
            count++;
          }

          var _target = target,
              pattern = _target.pattern;

          if ((0, _tsFns.isInstanceOf)(target, _dict.Dict) || (0, _tsFns.isInstanceOf)(target, _tuple.Tupl)) {
            return makeObj(pattern, path);
          } else if ((0, _tsFns.isInstanceOf)(target, _list.List)) {
            return makeArr(pattern, path);
          } else if ((0, _tsFns.isInstanceOf)(target, _enum.Enum)) {
            return makeEnum(pattern, path);
          } else if ((0, _tsFns.isInstanceOf)(target, _range.Range)) {
            var min = pattern.min,
                max = pattern.max;
            var tween = (max - min) * Math.random();
            var v = min + tween;
            return v;
          } else if ((0, _tsFns.isInstanceOf)(target, _mapping.Mapping)) {
            var _pattern = (0, _slicedToArray2.default)(pattern, 2),
                k = _pattern[0],
                _v = _pattern[1];

            var _count = parseInt(Math.random() * 10, 10) % _count;

            var mapping = {};

            for (var i = 0; i < _count; i++) {
              var key = createValue(k);
              var value = createValue(_v, makePath(path, k));
              mapping[key] = value;
            }

            return mapping;
          } else {
            return createValue(pattern, path);
          }
        } else if ((0, _tsFns.isInstanceOf)(target, _rule.Rule)) {
          var _target2 = target,
              name = _target2.name,
              _pattern2 = _target2.pattern,
              determine = _target2.determine;

          var rand = function rand() {
            return !!(parseInt(Math.random() * 10, 10) % 2);
          };

          if (name === 'ifexist' || name === 'shouldexist' || name === 'shouldnotexist') {
            if (rand()) {
              return createValue(_pattern2, path);
            } else {
              return;
            }
          } else if (name === 'equal') {
            return _pattern2;
          } else if (name === 'shouldnotmatch') {
            var allowed = [String, Number, Boolean, Date, Promise, Array, Object].filter(function (item) {
              return !(0, _tsFns.isEqual)(item, _pattern2);
            });
            return makeEnum(allowed, path);
          } else if (name === 'match') {
            return makeEnum(_pattern2, path);
          } else if (name === 'determine') {
            var chain = path.split('.');

            var _key2 = chain.pop();

            asyncs.push({
              path: chain.join('.'),
              // need to reback up level
              key: _key2,
              determine: determine
            });
          } else {
            return createValue(_pattern2, path);
          }
        } else if ((0, _tsFns.isObject)(target)) {
          return makeObj(target, path);
        } else if ((0, _tsFns.isArray)(target)) {
          return makeArr(target, path);
        } else {
          return create.call(_this, target, path, _this.loaders);
        }
      };

      var output = (0, _tsFns.isArray)(type) ? makeEnum(type) : createValue(type);

      if (asyncs.length) {
        asyncs.forEach(function (_ref) {
          var path = _ref.path,
              key = _ref.key,
              determine = _ref.determine;
          var data = !path ? output : (0, _tsFns.parse)(output, path);
          var type = determine(data);
          var v = createValue(type);
          (0, _tsFns.assign)(output, (0, _tsFns.makeKeyPath)([path, key]), v);
        });
      }

      return output;
    }
  }]);
  return Mocker;
}();

exports.Mocker = Mocker;
Mocker.defaultLoaders = [[String, function () {
  var length = parseInt(Math.random() * 200, 10);
  return (0, _tsFns.createRandomString)(length);
}], [_prototypes.String8, function () {
  return (0, _tsFns.createRandomString)(8);
}], [_prototypes.String16, function () {
  return (0, _tsFns.createRandomString)(16);
}], [_prototypes.String32, function () {
  return (0, _tsFns.createRandomString)(32);
}], [_prototypes.String64, function () {
  return (0, _tsFns.createRandomString)(64);
}], [_prototypes.String128, function () {
  return (0, _tsFns.createRandomString)(128);
}], [Number, function () {
  var random = createRandom();
  var maxNum = Number.MAX_SAFE_INTEGER;
  return random * maxNum;
}], [Boolean, function () {
  return !!(parseInt(Math.random() * 100, 10) % 2);
}], [_prototypes.Null, function () {
  return null;
}], [_prototypes.Undefined, function () {}], [_prototypes.None, function () {
  return [null][parseInt(Math.random() * 100, 10) % 2];
}], [Symbol, function () {
  return Symbol();
}], [Function, function () {
  return function (v) {
    return v;
  };
}], [Array, function () {
  var length = parseInt(Math.random() * 15, 10);
  var output = [];

  for (var i = 0; i < length; i++) {
    var o = this.mock([String, Number, Boolean, Date, Promise]);
    output.push(o);
  }

  return output;
}], [Object, function () {
  var length = parseInt(Math.random() * 15, 10);
  var output = {};

  for (var i = 0; i < length; i++) {
    var key = (0, _tsFns.createRandomString)(6);
    var value = this.mock([String, Number, Boolean, Date, Promise]);
    output[key] = value;
  }

  return output;
}], [_prototypes.Numeric, function () {
  return (createRandom(5) * Number.MAX_SAFE_INTEGER).toString();
}], [_prototypes.Int, function () {
  return parseInt(createRandom(5) * Number.MAX_SAFE_INTEGER, 10);
}], [_prototypes.Float, function () {
  return createRandom(5) * Number.MAX_SAFE_INTEGER * 0.12;
}], [_prototypes.Negative, function () {
  return -createRandom(5) * Number.MAX_SAFE_INTEGER;
}], [_prototypes.Positive, function () {
  return createRandom(5) * Number.MAX_SAFE_INTEGER;
}], [_prototypes.Zero, function () {
  return 0;
}], [_prototypes.Natural, function () {
  return parseInt(createRandom(5) * Number.MAX_SAFE_INTEGER, 10) + 1;
}], [_prototypes.Any, function () {
  return this.mock([String, Number, Boolean, Date, Promise, Array, Object]);
}], function (target, path, next) {
  if ((0, _tsFns.isNaN)(target)) {
    return NaN;
  }

  next();
}, [Infinity, function () {
  return Infinity;
}], [_prototypes.Finity, function () {
  return createRandom(5) * Number.MAX_SAFE_INTEGER;
}], [Date, function () {
  return new Date();
}], [Promise, function () {
  return Promise.resolve(this.mock(String));
}]];

function createRandom() {
  var f = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 3;
  var random = 1;

  for (var i = 0; i < f; i++) {
    random = random * Math.random() * 1 / (i * 5 + 1);
  }

  return random;
}

function create(target, path, loaders) {
  if ((0, _tsFns.isArray)(target)) {
    var protos = target;
    var length = protos.length;
    var index = parseInt(Math.random() * 10, 10) % length;
    var proto = protos[index];
    return create.call(this, proto, path, loaders);
  }

  for (var i = 0, len = loaders.length; i < len; i++) {
    var item = loaders[i];

    if ((0, _tsFns.isFunction)(item)) {
      var notFound = false;

      var next = function next() {
        notFound = true;
      };

      var output = item.call(this, target, path, next);

      if (!notFound) {
        return output;
      }
    } else if ((0, _tsFns.isArray)(item)) {
      var _item = (0, _slicedToArray2.default)(item, 2),
          _proto = _item[0],
          fn = _item[1];

      if ((0, _tsFns.isObject)(target) && target['!']) {
        var excludes = target['!'];

        if (excludes.includes(_proto)) {
          continue;
        }

        return fn.call(this, target, path);
      } else if (target === _proto) {
        return fn.call(this, target, path);
      }
    }
  }

  return target;
}