'use strict';

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

var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _createClass = require('@babel/runtime/helpers/createClass');
var signature_js = require('ethereumjs-util/dist/signature.js');
var hash_js = require('ethereumjs-util/dist/hash.js');
var bytes_js = require('ethereumjs-util/dist/bytes.js');
var secp256k1 = require('secp256k1');
var minterjsTx = require('minterjs-tx');
var minterjsUtil = require('minterjs-util');
var utils = require('./utils.js');

var Check = /*#__PURE__*/function () {
  function Check(data) {
    _classCallCheck(this, Check);
    data = data || {};
    if (typeof data === 'string') {
      data = minterjsUtil.mPrefixStrip(data);
    }

    // Define Properties
    var fields = [{
      name: 'nonce',
      length: 16,
      allowLess: true
    }, {
      name: 'chainId',
      length: 1
    }, {
      name: 'dueBlock',
      length: 8,
      allowLess: true
    }, {
      name: 'coin',
      length: 4,
      allowLess: true
    }, {
      name: 'value',
      length: 32,
      allowLess: true
    }, {
      name: 'gasCoin',
      length: 4,
      allowLess: true
    }, {
      name: 'lock',
      allowZero: true,
      allowLess: true,
      length: 65,
      "default": Buffer.from([])
    }, {
      name: 'v',
      allowZero: true,
      "default": Buffer.from([0x1c])
    }, {
      name: 'r',
      length: 32,
      allowZero: true,
      allowLess: true,
      "default": Buffer.from([])
    }, {
      name: 's',
      length: 32,
      allowZero: true,
      allowLess: true,
      "default": Buffer.from([])
    }];

    /**
     * Returns the rlp encoding of the transaction
     * @method serialize
     * @return {Buffer}
     * @memberof Transaction
     * @name serialize
     */
    // attached serialize
    minterjsTx.defineProperties(this, fields, data);
  }
  _createClass(Check, [{
    key: "hash",
    value: function hash() {
      // don't hash last 4 fields (lock and signature)
      return hash_js.rlphash(this.raw.slice(0, -4));
    }
  }, {
    key: "sign",
    value: function sign(privateKey, password) {
      var messageHash = this.hash(false);
      if (typeof password === 'string') {
        password = Buffer.from(password, 'utf8');
      }
      var passwordBuffer = hash_js.sha256(password);
      var lock = secp256k1.ecdsaSign(messageHash, passwordBuffer);
      /** @type {Buffer} */
      var lockWithRecovery = Buffer.alloc(65);
      lockWithRecovery.set(lock.signature, 0);
      lockWithRecovery[64] = lock.recid;
      this.lock = "0x".concat(lockWithRecovery.toString('hex'));

      // don't hash last 3 signature fields
      var messageHashWithLock = hash_js.rlphash(this.raw.slice(0, -3));
      var sig = signature_js.ecsign(messageHashWithLock, privateKey);
      Object.assign(this, sig);
    }
  }]);
  return Check;
}();
/**
 * @param {object} params
 * @param {string} [params.seedPhrase]
 * @param {string|Buffer} [params.privateKey] - hex or Buffer
 * @param {string} params.password - utf8
 * @param {string} params.nonce
 * @param {number} [params.chainId=1]
 * @param {number|string} params.coin
 * @param {number|string} params.value
 * @param {number|string} params.gasCoin
 * @param {number} [params.dueBlock=999999999]
 * @param {boolean} [isReturnObject]
 * @return {string|Check}
 */
function issueCheck() {
  var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
    seedPhrase = _ref.seedPhrase,
    privateKey = _ref.privateKey,
    password = _ref.password,
    nonce = _ref.nonce,
    _ref$chainId = _ref.chainId,
    chainId = _ref$chainId === void 0 ? 1 : _ref$chainId,
    coin = _ref.coin,
    value = _ref.value,
    _ref$gasCoin = _ref.gasCoin,
    gasCoin = _ref$gasCoin === void 0 ? 0 : _ref$gasCoin,
    _ref$dueBlock = _ref.dueBlock,
    dueBlock = _ref$dueBlock === void 0 ? 999999999 : _ref$dueBlock;
  var isReturnObject = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  utils.validateUint(dueBlock, 'dueBlock');
  utils.validateUint(coin, 'coin');
  utils.validateUint(gasCoin, 'gasCoin');
  utils.validateAmount(value, 'value');
  if (!seedPhrase && !privateKey) {
    throw new Error('seedPhrase or privateKey are required');
  }
  if (!privateKey && seedPhrase) {
    privateKey = utils.getPrivateKeyFromSeedPhrase(seedPhrase);
  }
  privateKey = bytes_js.toBuffer(privateKey);
  var check = new Check({
    nonce: Buffer.from(nonce.toString(), 'utf8'),
    chainId: utils.integerToHexString(chainId),
    coin: utils.integerToHexString(coin),
    value: "0x".concat(minterjsUtil.convertToPip(value, 'hex')),
    gasCoin: utils.integerToHexString(gasCoin),
    dueBlock: utils.integerToHexString(dueBlock)
  });
  check.sign(privateKey, password);
  return isReturnObject ? check : "Mc".concat(check.serialize().toString('hex'));
}

/**
 * @param {string} rawCheck
 */
function decodeCheck(rawCheck) {
  var check = new Check(rawCheck);
  return {
    nonce: check.nonce.toString('utf8'),
    chainId: utils.bufferToInteger(check.chainId),
    coin: utils.bufferToInteger(check.coin),
    value: minterjsUtil.convertFromPip(utils.bufferToInteger(check.value)),
    gasCoin: utils.bufferToInteger(check.gasCoin),
    dueBlock: utils.bufferToInteger(check.dueBlock)
  };
}

/**
 * @param {string|Buffer} rawCheck
 * @return {string}
 */
function getGasCoinFromCheck(rawCheck) {
  try {
    var check = new Check(minterjsUtil.toBuffer(rawCheck));
    return utils.bufferToInteger(check.gasCoin);
  } catch (error) {
    error.message = "Can't decode check: ".concat(error.message);
    throw error;
  }
}

exports.decodeCheck = decodeCheck;
exports.default = issueCheck;
exports.getGasCoinFromCheck = getGasCoinFromCheck;
