'use strict';

var Message = Message || require('./Message');

var RootCerts = require('./common/RootCerts');

var PayPro = require('./common/PayPro');

var KJUR = require('jsrsasign');

var asn1 = require('asn1.js');
var rfc3280 = require('asn1.js/rfc/3280');
var Certificate = rfc3280.Certificate;

PayPro.prototype.x509Sign = function(key) {
  var self = this;
  var crypto = require('crypto');
  var pki_type = this.get('pki_type');
  var pki_data = this.get('pki_data'); // contains one or more x509 certs
  pki_data = PayPro.X509Certificates.decode(pki_data);
  pki_data = pki_data.certificate;
  var details = this.get('serialized_payment_details');
  var type = pki_type.split('+')[1].toUpperCase();

  var trusted = pki_data.map(function(cert) {
    var der = cert.toString('hex');
    var pem = self._DERtoPEM(der, 'CERTIFICATE');
    return RootCerts.getTrusted(pem);
  });

  // XXX Figure out what to do here
  if (!trusted.length) {
    // throw new Error('Unstrusted certificate.');
  } else {
    trusted.forEach(function(name) {
      // console.log('Certificate: %s', name);
    });
  }

  var signature = crypto.createSign('RSA-' + type);
  var buf = this.serializeForSig();
  signature.update(buf);
  var sig = signature.sign(key);
  return sig;
};

PayPro.prototype.x509Verify = function() {
  var self = this;
  var crypto = require('crypto');
  var pki_type = this.get('pki_type');
  var sig = this.get('signature');
  var pki_data = this.get('pki_data');
  pki_data = PayPro.X509Certificates.decode(pki_data);
  pki_data = pki_data.certificate;
  var details = this.get('serialized_payment_details');
  var buf = this.serializeForSig();
  var type = pki_type.split('+')[1].toUpperCase();

  var verifier = crypto.createVerify('RSA-' + type);
  verifier.update(buf);

  var signedCert = pki_data[0];
  var der = signedCert.toString('hex');
  var pem = this._DERtoPEM(der, 'CERTIFICATE');
  var verified = verifier.verify(pem, sig);

  var chain = pki_data;

  // Verifying the cert chain:
  // 1. Extract public key from next certificate.
  // 2. Extract signature from current certificate.
  // 3. If current cert is not trusted, verify that the current cert is signed
  //    by NEXT by the certificate.
  // 4. XXX What to do when the certificate is revoked?

  var blen = +type.replace(/[^\d]+/g, '');
  if (blen === 1) blen = 20;
  if (blen === 256) blen = 32;

  chain.forEach(function(cert, i) {
    var der = cert.toString('hex');
    var pem = self._DERtoPEM(der, 'CERTIFICATE');
    var name = RootCerts.getTrusted(pem);

    var ncert = chain[i + 1];
    // The root cert, check if it's trusted:
    if (!ncert || name) {
      return;
    }
    var nder = ncert.toString('hex');
    var npem = self._DERtoPEM(nder, 'CERTIFICATE');

    // Get public key from next certificate.
    var data = new Buffer(nder, 'hex');
    var nc = Certificate.decode(data, 'der');
    var npubKey = nc.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
    npubKey = self._DERtoPEM(npubKey, 'RSA PUBLIC KEY');

    // Get signature from current certificate.
    var data = new Buffer(der, 'hex');
    var c = Certificate.decode(data, 'der');
    var sig = c.signature.data;

    var verifier = crypto.createVerify('RSA-' + type);

    // Create a To-Be-Signed Certificate using asn1.js:
    // Fails at Issuer:
    var tbs = rfc3280.TBSCertificate.encode(c.tbsCertificate, 'der');
    verifier.update(tbs);

    var v = verifier.verify(npubKey, sig);
    if (!v) {
      verified = false;
    }
  });

  return verified;
};

module.exports = PayPro;

@@ -2231,10 +2231,13 @@
  // 
-4.
+NOTE:
  XXX
@@ -2292,121 +2292,35 @@
 var 
-blen = +type.replace(/%5B%5E%5Cd%5D+/g, '');%0A  if (blen === 1) blen = 20;%0A  if (blen === 256) blen = 32;%0A%0A  chain.forEach
+chainVerified = chain.every
 (fun
@@ -2562,24 +2562,48 @@
  %7C%7C name) %7B%0A
+      chain.length = 0;%0A
       return
@@ -2602,16 +2602,21 @@
   return
+ true
 ;%0A    %7D%0A
@@ -2741,33 +2741,33 @@
 next certificate
-.
+:
 %0A    var data = 
@@ -3020,17 +3020,17 @@
 tificate
-.
+:
 %0A    var
@@ -3236,16 +3236,26 @@
 ificate 
+to verify 
 using as
@@ -3390,15 +3390,14 @@
     
-var v =
+return
  ver
@@ -3430,67 +3430,40 @@
 ;%0A  
-  if (!v) %7B%0A      verified = false;%0A    %7D%0A  %7D);%0A%0A  return v
+%7D);%0A%0A  return verified && chainV
 erif

verify chain refactor.