import { helper } from '@ember/component/helper';
import * as asn1js from 'asn1js';
import { fromBase64, stringToArrayBuffer } from 'pvutils';
import { Certificate } from 'pkijs';

export function parsePkiCert([model]) {
  // model has to be the responseJSON from PKI serializer
  // return if no certificate or if the "certificate" is actually a CRL
  if (!model.certificate || model.certificate.includes('BEGIN X509 CRL')) {
    return;
  }
  let cert;
  try {
    let cert_base64 = model.certificate.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, '');
    let cert_der = fromBase64(cert_base64);
    let cert_asn1 = asn1js.fromBER(stringToArrayBuffer(cert_der));
    cert = new Certificate({ schema: cert_asn1.result });
  } catch (error) {
    console.debug('DEBUG: Parsing Certificate', error);
    return {
      can_parse: false,
    };
  }

  // We wish to get the CN element out of this certificate's subject. A
  // subject is a list of RDNs, where each RDN is a (type, value) tuple
  // and where a type is an OID. The OID for CN can be found here:
  //
  //    http://oid-info.com/get/2.5.4.3
  //    https://datatracker.ietf.org/doc/html/rfc5280#page-112
  //
  // Each value is then encoded as another ASN.1 object; in the case of a
  // CommonName field, this is usually a PrintableString, BMPString, or a
  // UTF8String. Regardless of encoding, it should be present in the
  // valueBlock's value field if it is renderable.
  const commonNameOID = '2.5.4.3';
  const commonNames = cert?.subject?.typesAndValues
    .filter((rdn) => rdn?.type === commonNameOID)
    .map((rdn) => rdn?.value?.valueBlock?.value);

  // Theoretically, there might be multiple (or no) CommonNames -- but Vault
  // presently refuses to issue certificates without CommonNames in most
  // cases. For now, return the first CommonName we find. Alternatively, we
  // might update our callers to handle multiple, or join them using some
  // separator like ','.
  const commonName = commonNames ? (commonNames.length ? commonNames[0] : null) : null;

  // Date instances are stored in the value field as the notAfter/notBefore
  // field themselves are Time values.
  const expiryDate = cert?.notAfter?.value;
  const issueDate = cert?.notBefore?.value;
  return {
    can_parse: true,
    common_name: commonName,
    expiry_date: expiryDate,
    issue_date: issueDate,
  };
}

export default helper(parsePkiCert);
