const crypto = require('crypto');
const simpleEncryptor = require('simple-encryptor');
const fs = require('fs');
const path = require('path');
const _ = require('lodash');

const { datadir } = require('./directories');

const defaultEncryptionKey = 'mQAUaXhavRGJDxDTXSCg7Ej0xMmGCrx6OKA07DIMBiDcYYkvkaXjTAzPUEHEHEf9';

let _encryptionKey = null;

function loadEncryptionKey() {
  if (_encryptionKey) {
    return _encryptionKey;
  }
  const encryptor = simpleEncryptor.createEncryptor(defaultEncryptionKey);

  const keyFile = path.join(datadir(), '.key');

  if (!fs.existsSync(keyFile)) {
    const generatedKey = crypto.randomBytes(32);
    const newKey = generatedKey.toString('hex');
    const result = {
      encryptionKey: newKey,
    };
    fs.writeFileSync(keyFile, encryptor.encrypt(result), 'utf-8');
  }

  const encryptedData = fs.readFileSync(keyFile, 'utf-8');
  const data = encryptor.decrypt(encryptedData);
  _encryptionKey = data['encryptionKey'];
  return _encryptionKey;
}

let _encryptor = null;

function getEncryptor() {
  if (_encryptor) {
    return _encryptor;
  }
  _encryptor = simpleEncryptor.createEncryptor(loadEncryptionKey());
  return _encryptor;
}

function encryptPasswordField(connection, field) {
  if (
    connection &&
    connection[field] &&
    !connection[field].startsWith('crypt:') &&
    connection.passwordMode != 'saveRaw'
  ) {
    return {
      ...connection,
      [field]: 'crypt:' + getEncryptor().encrypt(connection[field]),
    };
  }
  return connection;
}

function decryptPasswordField(connection, field) {
  if (connection && connection[field] && connection[field].startsWith('crypt:')) {
    return {
      ...connection,
      [field]: getEncryptor().decrypt(connection[field].substring('crypt:'.length)),
    };
  }
  return connection;
}

function encryptConnection(connection) {
  connection = encryptPasswordField(connection, 'password');
  connection = encryptPasswordField(connection, 'sshPassword');
  connection = encryptPasswordField(connection, 'sshKeyfilePassword');
  return connection;
}

function maskConnection(connection) {
  if (!connection) return connection;
  return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']);
}

function decryptConnection(connection) {
  connection = decryptPasswordField(connection, 'password');
  connection = decryptPasswordField(connection, 'sshPassword');
  connection = decryptPasswordField(connection, 'sshKeyfilePassword');
  return connection;
}

function pickSafeConnectionInfo(connection) {
  return _.mapValues(connection, (v, k) => {
    if (k == 'engine' || k == 'port' || k == 'authType' || k == 'sshMode' || k == 'passwordMode') return v;
    if (v === null || v === true || v === false) return v;
    if (v) return '***';
    return undefined;
  });
}

module.exports = {
  loadEncryptionKey,
  encryptConnection,
  decryptConnection,
  maskConnection,
  pickSafeConnectionInfo,
};
