const ChainUtil = require('../util/chain-util');

const outputValidation = {
  publicKey: ChainUtil.validateIsPublicKey,
  amount: ChainUtil.createValidateIsIntegerWithMin(1)
};

function validateOutputs(t) {
  let validateRes = ChainUtil.validateArray(t, function (output) {
      return ChainUtil.validateObject(output, outputValidation);
    });
  if (!validateRes.result) {
    return validateRes
  }

  if (t.length <= 0) {
    return {
      result: false,
      reason: "Outputs length isn't positive"
    };
  }

  return {
    result: true
  };
}

const baseValidation = {
  input: ChainUtil.validateIsPublicKey,
  counter: ChainUtil.createValidateIsIntegerWithMin(1),
  rewardAmount: ChainUtil.createValidateIsIntegerWithMin(0),
  outputs: validateOutputs,
  signature: ChainUtil.validateIsSignature
}

class Payment {
  constructor(senderKeyPair, counter, outputs, rewardAmount) {
    this.input = senderKeyPair.getPublic().encode('hex');
    this.counter = counter;
    this.rewardAmount = rewardAmount;
    this.outputs = outputs;
    this.signature = senderKeyPair.sign(Payment.hashToSign(this));

    const verification = Payment.verify(this);
    if (!verification.result) {
      throw new Error(verification.reason);
    }
  }

  static hashToSign(transaction) {
    return ChainUtil.hash([
      transaction.counter,
      transaction.rewardAmount,
      transaction.outputs]);
  }

  static createOutput(recipient, amount) {
    return {
      publicKey: recipient,
      amount: amount
    };
  }

  static verify(transaction) {
    const validationRes = ChainUtil.validateObject(transaction, baseValidation);
    if (!validationRes.result) {
      return validationRes;
    }

    const verifyRes = ChainUtil.verifySignature(
      transaction.input,
      transaction.signature,
      Payment.hashToSign(transaction));
    if (!verifyRes.result) {
      return verifyRes;
    }

    return {
      result: true,
    };
  }

  static name() {
    return "Payment";
  }
}

module.exports = Payment;