'use strict';

var _createClass = require('@babel/runtime/helpers/createClass');
var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var bytes_js = require('ethereumjs-util/dist/bytes.js');
var rlp = require('rlp');
var ethjsUtil = require('ethjs-util');
var minterjsTx = require('minterjs-tx');
var minterjsUtil = require('minterjs-util');
var index = require('./tx-data/index.js');
var redeemCheck = require('./tx-data/redeem-check.js');
var utils = require('./utils.js');

var DEFAULT_LINK_HOST = 'https://bip.to';
var Link = /*#__PURE__*/_createClass(function Link(data) {
  _classCallCheck(this, Link);
  data = data || {};

  // Define Properties
  var fields = [{
    name: 'type',
    length: 1
  }, {
    name: 'data',
    alias: 'input'
  }, {
    name: 'payload',
    allowZero: true,
    "default": Buffer.from([])
  }, {
    name: 'nonce',
    length: 32,
    allowLess: true
  }, {
    name: 'gasPrice',
    length: 32,
    allowLess: true
  }, {
    name: 'gasCoin',
    length: 4,
    allowLess: true,
    storeNullAsArray: true
  }];

  /**
   * Returns the rlp encoding of the transaction
   * @method serialize
   * @return {Buffer}
   * @memberof Transaction
   * @name serialize
   */
  // attached serialize
  minterjsTx.defineProperties(this, fields, data);
});
/**
 * @typedef {object} LinkParams
 * @property {number|string} [nonce]
 * @property {number|string} [gasPrice]
 * @property {number|string} [gasCoin]
 * @property {string|Buffer|TX_TYPE} type
 * @property {string|Buffer|TX_TYPE} [txType] - deprecated
 * @property {Buffer|object|TxData} data
 * @property {Buffer} [txData] - deprecated
 * @property {string} [payload]
 * @property {string} [message] - deprecated
 * @property {string} [password]
 */
/**
 * @param {LinkParams} txParams
 * @param {string} [linkHost]
 * @return {string}
 */
function prepareLink() {
  var txParams = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var linkHost = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_LINK_HOST;
  var nonce = txParams.nonce,
    gasPrice = txParams.gasPrice,
    gasCoin = txParams.gasCoin,
    type = txParams.type,
    txType = txParams.txType,
    data = txParams.data,
    txData = txParams.txData,
    password = txParams.password;
  var txProps = {
    nonce: nonce || nonce === 0 ? utils.integerToHexString(nonce) : undefined,
    gasPrice: gasPrice || gasPrice === 0 ? utils.integerToHexString(gasPrice) : undefined,
    gasCoin: gasCoin || gasCoin === 0 ? utils.integerToHexString(gasCoin) : undefined,
    type: type || txType,
    data: index.ensureBufferData(data || txData, type || txType)
  };

  // eslint-disable-next-line unicorn/consistent-destructuring
  var payload = txParams.message || txParams.payload;
  if (payload) {
    if (typeof payload === 'string') {
      payload = Buffer.from(payload, 'utf8');
    }
    txProps.payload = payload;
  }

  // ensure no ending slash
  linkHost = linkHost.replace(/\/$/, '');
  // ensure scheme
  if (linkHost.indexOf('://') === -1) {
    linkHost = "https://".concat(linkHost);
  }
  var tx = new Link(txProps);
  var result = "".concat(linkHost, "/tx/").concat(base64urlEncode(tx.serialize()));
  if (password) {
    result += "?p=".concat(base64urlEncode(toBuffer(password)));
  }
  return result;
}

/**
 * @param {string} url
 * @param {object} [options]
 * @param {string} [options.address]
 * @param {string} [options.seedPhrase]
 * @param {string} [options.privateKey]
 * @param {boolean} [options.decodeCheck]
 * @return {TxParams}
 */
function decodeLink(url) {
  var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
    address = _ref.address,
    seedPhrase = _ref.seedPhrase,
    privateKey = _ref.privateKey,
    decodeCheck = _ref.decodeCheck;
  var txBase64 = url.replace(/^.*\/tx\//, '').replace(/\?.*$/, '');
  var txBytes = rlp.decode(base64urlDecode(txBase64));
  var passwordBase64 = url.search(/[?&]p=/) >= 0 ? url.replace(/^.*[?&]p=/, '') : '';
  var password = passwordBase64 ? Buffer.from(base64urlDecode(passwordBase64)) : '';
  var tx = new Link(txBytes);
  var txType = minterjsUtil.normalizeTxType(tx.type);
  if (txType === minterjsUtil.TX_TYPE.REDEEM_CHECK && password) {
    if (!seedPhrase && !privateKey && !address) {
      throw new Error('address or seedPhrase or privateKey are required if link has password');
    }

    // get check from data
    var _TxDataRedeemCheck = new minterjsTx.TxDataRedeemCheck(tx.data),
      check = _TxDataRedeemCheck.check;
    // proof from password
    var _txData = new redeemCheck({
      check: check
    }, {
      password: password,
      address: address,
      seedPhrase: seedPhrase,
      privateKey: privateKey
    }).serialize();
    tx.data = _txData;
  }
  var txData = index.decodeTxData(tx.type, tx.data, {
    decodeCheck: decodeCheck
  });
  return {
    nonce: tx.nonce.length > 0 ? utils.bufferToInteger(tx.nonce) : undefined,
    gasPrice: tx.gasPrice.length > 0 ? utils.bufferToInteger(tx.gasPrice) : undefined,
    // [] === undefined, <Buffer > === 0
    gasCoin: Array.isArray(tx.gasCoin) ? undefined : utils.bufferToInteger(tx.gasCoin),
    type: txType,
    data: txData,
    payload: tx.payload.toString('utf8')
  };
}

/**
 * @param {ByteArray} byteArray
 */
function base64urlEncode(byteArray) {
  return Buffer.from(byteArray).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}

/**
 * @param {string} base64urlString
 */
function base64urlDecode(base64urlString) {
  var padModulus = base64urlString.length % 4;
  var padLength = padModulus ? 4 - padModulus : 0;
  var pad = Array.from({
    length: padLength
  }, function () {
    return '=';
  }).join('');
  return Buffer.from(base64urlString + pad, 'base64');
}

/**
 * toBuffer which supports UTF8 strings
 * @param {ToBufferInputTypes} value
 * @return {Buffer}
 */
function toBuffer(value) {
  return typeof value === 'string' && !ethjsUtil.isHexPrefixed(value) ? Buffer.from(value, 'utf8') : bytes_js.toBuffer(value);
}

exports.decodeLink = decodeLink;
exports.prepareLink = prepareLink;
