import libCoverage from 'istanbul-lib-coverage';
import libReport from 'istanbul-lib-report';
import reports from 'istanbul-reports';
import { glob } from "../lib/builderator.js";
import fs from "fs";
import v8toIstanbul from 'v8-to-istanbul';
import assert from "assert";
import url from "url";
import normalize from "normalize-path";

export const description = "Takes the output of a nv8 coverage directory and generates a report.";

export const argument = ["<coverage_dir>", "coverage directory"];

export const main = async (coverage_dir) => {
  const covdir = normalize(coverage_dir);
  const covpattern = `${covdir}/**/*.json`;
  console.log(`Searching ${covpattern} for coverage files...`);

  const covfiles = glob(covpattern);
  console.log(`Found ${covfiles.length} .json files in ${covdir}`);

  const coverage = {};

  const excludes = [
    "node_modules",
    "secrets",
    "/net"
  ];

  for(const fname of covfiles) {
    const data = JSON.parse(fs.readFileSync(fname));

    // test removing just node modules
    data.result = data.result.filter(x => {
      if(x.url) {
        // we need to do surgery on the URL because node is bad at them
        let pathname = url.parse(x.url).pathname;

        // fix the URL and turn it into a file name
        if(!pathname) {
          return false;
        } else if(pathname.startsWith("/C:")) {
          // why does url not parse windows paths right?
          // remove the leading / so it's parsed correctly
          x.url = pathname.slice(1);
        } else {
          x.url = pathname;
        }

        const excluded = excludes.filter(e => x.url.includes(e));
        return excluded.length === 0 && fs.existsSync(x.url);
      } else {
        return false;
      }
    });

    // looks good, save it
    if(data.result.length > 0) {
      coverage[fname] = data;
    }
  }

  const coverageMap = libCoverage.createCoverageMap();
  console.log("After filtering, found count is:", Object.entries(coverage).length);

  for(const [fname, data] of Object.entries(coverage)) {
    for(const entry of data.result) {
      let converter;
      const pathname = url.parse(entry.url).pathname
      assert(fs.existsSync(pathname), `coverage entry in ${fname} contains ${entry.url} that doesn't exist but should`);

      converter = v8toIstanbul(pathname, 0, {source: entry.source}, path => {
          const excluded = excludes.filter(e => path.includes(e));
          return excluded.length > 0;
      });

      try {
        await converter.load();
        converter.applyCoverage(entry.functions);
        coverageMap.merge(converter.toIstanbul());
      } catch(error) {
        console.error(error, "load", entry.url);
      }
    }
  }

  const watermarks = undefined; // used in check coverage ignored here

  const context = libReport.createContext({
    dir: "coverage",
    watermarks,
    coverageMap
  });

  ["text","html"].forEach(format => {
    reports.create(format, {
      skipEmpty: false,
      skipFull: true,
      maxCols: 100
    }).execute(context);
  });

  process.exit(0);
}
