'use strict';

// GLOBAL
const path = require('path');
const execa = require('execa');

// LOCAL
const tools = require('../../utils/tools');
const notificationUtils = require('../../utils/notification/notification-utils');
const configUtils = require('../config/config-utils');
const initUtils = require('../init/init-utils');

// GET ARGS
const { dryRun, skipAudit } = tools.getArgs();



const getVulnerabilitiesList = () => {
  let auditContent;
  const auditFile = path.join(process.cwd(), 'audit.json');

  if (tools.isFileExists(auditFile)) {
    auditContent = tools.getFileContent(auditFile);
  } else {
    tools.logWarning(`${auditFile} not found... unable to precess audit content`);
    return null;
  }

  let auditContentArray = [];
  let parsedOutput = {
    "auditSummary": {},
    "vulnerabilities": {}
  };

  // yarn audit output uses a specific json-lines format, we need to split it first
  auditContentArray = auditContent.split('\n');

  // extracting the audit summary lines
  auditContentArray.forEach((c) => {
    try {
      const parsedContent = JSON.parse(c);
      if (parsedContent) {
        if (parsedContent.type === 'auditSummary') {
          parsedOutput['auditSummary'] = parsedContent.data.vulnerabilities;
        } else {
          // console.log(parsedContent);
          const auditData = parsedContent.data;

          parsedOutput.vulnerabilities[`${auditData.resolution.id} ${auditData.advisory.module_name} ${auditData.resolution.path}`] =  {
            "module_name": auditData.advisory.module_name,
            "severity": auditData.advisory.severity,
            "path": auditData.resolution.path,
            "title": auditData.advisory.title,
            "recommendation": auditData.advisory.recommendation,
            "patched_versions":auditData.advisory.patched_versions,
            "vulnerable_versions": auditData.advisory.vulnerable_versions
          }
        }
      }
    } catch(e) {
      // console.log(e);
    } // it can fail
  })

  return parsedOutput;
}


module.exports.audit = (pkg) => {
  tools.logTitle('Yarn auditing package');

  let outReport;

  if (skipAudit) {
    tools.logInfo('Skipping audit...');
    return Promise.resolve();
  }

  return Promise.resolve()
    // extract the audit summary lines
    .then(() => {
      return Promise.resolve()
        .then(() => {
          const auditFile = path.join(process.cwd(), 'audit.json');
          tools.logInfo(`Creating audit file`)
          return execa.shellSync(`yarn audit --level high --json > ${auditFile}`, { cwd: process.cwd(), stdio: 'inherit' });
        })
        .then(() => {
          tools.logSuccess();
          return null;
        })
        .catch((e) => {
          tools.logError('Auditing detected vulnerabilities in dependencies');
          return getVulnerabilitiesList();
        })
    })

    // sending output to slack channel
    .then((vulnerabilityReport) => {

      outReport = vulnerabilityReport;

      if (!vulnerabilityReport) {
        tools.logSuccess('OK, no vulnerabilities detected');

        if (pkg) {
          return notificationUtils.package.sendPackageMessage({
            package: pkg,
            text: 'Dependencies audit : NO vulnerabilities detected'
          });
        }

      } else {
        tools.logWarning(JSON.stringify(vulnerabilityReport, null, 2));

        let message = '';
        Object.entries(vulnerabilityReport.auditSummary).forEach((v) => {
          message += `${v[0]}:*${v[1]}* `;
        });

        if (pkg) {
          return notificationUtils.package.sendPackageMessage({
            package: pkg,
            text: `Dependencies audit detected vulnerabilities : ${message}`
          });
        }
      }
    })

    .then(() => {
      if (!outReport) {
        return;
      }

      // getting config options for gates defined
      let configOptions;

      if (pkg.standalone) {
        // TODO proceed to gates checks if needed
        // configOptions = configUtils.global.getConfigOptionsStandalone();
        return;
      } else {
        configOptions = configUtils.global.getConfigOptions();
      }

      // getting local csdr euiVersion
      const euiVersion = configUtils.global.getLocalEuiVersion();

      // if eUI version not found, no action
      if (!euiVersion) {
        return;
      }

      // getting gates for euiVersion found
      const gates = configOptions.AUDIT_DEPENDENCIES_GATES ? configOptions.AUDIT_DEPENDENCIES_GATES[euiVersion]: undefined;

      tools.logTitle(`Checking audit dependencies gates for local euiVersion : ${euiVersion}`);

      // if no gates found for corresponding version, no action
      if (!gates) {
        tools.logInfo('No gates found for local eUI version...skipping');
        return;
      }

      tools.logInfo(`Based on summary : ${JSON.stringify(outReport.auditSummary)}`);
      tools.logInfo(`Gates found : ${JSON.stringify(gates)}`);

      // checking gates level if any
      let gatesPassed = true;

      Object.keys(outReport.auditSummary).forEach((level) => {
        tools.logInfo(`Checking audit level : ${level} - item found ${outReport.auditSummary[level]}`);

        if (gates[level] === undefined) {
          tools.logInfo(`No gates found for level`);
          tools.logInfo(`===> PASSED`);
        } else {
          tools.logInfo(`Gates found for level maxium allowed : ${gates[level]}`);
          if (outReport.auditSummary[level] > gates[level]) {
            tools.logError(`===> FAILED`);
            gatesPassed = false;
          } else {
            tools.logInfo(`===> PASSED`);
          }
        }
      })

      if (!gatesPassed) {
        throw new Error('AUDIT_DEPENDENCIES_GATES_FAILED');
      }
    })

    .catch((e) => {
      throw e;
    })
}
