"use strict";

const forge = require('node-forge');

const fs = require('fs');

const mkdirp = require('mkdirp');

const path = require('path');

const logger = require('@parcel/logger');

function generateCertificate(options = {}) {
  const privateKeyPath = path.join(options.cacheDir, 'private.pem');
  const certPath = path.join(options.cacheDir, 'primary.crt');

  if (options.cache) {
    const cachedKey = fs.existsSync(privateKeyPath) && fs.readFileSync(privateKeyPath);
    const cachedCert = fs.existsSync(certPath) && fs.readFileSync(certPath);

    if (cachedKey && cachedCert) {
      return {
        key: cachedKey,
        cert: cachedCert
      };
    }
  }

  logger.progress('Generating SSL Certificate...');
  const pki = forge.pki;
  const keys = pki.rsa.generateKeyPair(2048);
  const cert = pki.createCertificate();
  cert.publicKey = keys.publicKey;
  cert.serialNumber = Date.now().toString();
  cert.validity.notBefore = new Date();
  cert.validity.notAfter = new Date();
  cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
  const attrs = [{
    name: 'commonName',
    value: 'parceljs.org'
  }, {
    name: 'countryName',
    value: 'US'
  }, {
    shortName: 'ST',
    value: 'Virginia'
  }, {
    name: 'localityName',
    value: 'Blacksburg'
  }, {
    name: 'organizationName',
    value: 'parcelBundler'
  }, {
    shortName: 'OU',
    value: 'Test'
  }];
  cert.setSubject(attrs);
  cert.setIssuer(attrs);
  cert.setExtensions([{
    name: 'basicConstraints',
    cA: true
  }, {
    name: 'keyUsage',
    keyCertSign: true,
    digitalSignature: true,
    nonRepudiation: true,
    keyEncipherment: true,
    dataEncipherment: true
  }, {
    name: 'extKeyUsage',
    serverAuth: true,
    clientAuth: true,
    codeSigning: true,
    emailProtection: true,
    timeStamping: true
  }, {
    name: 'nsCertType',
    client: true,
    server: true,
    email: true,
    objsign: true,
    sslCA: true,
    emailCA: true,
    objCA: true
  }, {
    name: 'subjectAltName',
    altNames: [{
      type: 6,
      // URI
      value: 'http://example.org/webid#me'
    }, {
      type: 7,
      // IP
      ip: '127.0.0.1'
    }]
  }, {
    name: 'subjectKeyIdentifier'
  }]);
  cert.sign(keys.privateKey, forge.md.sha256.create());
  const privPem = pki.privateKeyToPem(keys.privateKey);
  const certPem = pki.certificateToPem(cert);

  if (options.cache) {
    mkdirp.sync(options.cacheDir);
    fs.writeFileSync(privateKeyPath, privPem);
    fs.writeFileSync(certPath, certPem);
  }

  return {
    key: privPem,
    cert: certPem
  };
}

module.exports = generateCertificate;