/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

const minimatch = require('minimatch');
const fs = require('fs');
const path = require('path');
const iLibInstrument = require('istanbul-lib-instrument');
const iLibCoverage = require('istanbul-lib-coverage');
const iLibSourceMaps = require('istanbul-lib-source-maps');
const iLibReport = require('istanbul-lib-report');
const iReports = require('istanbul-reports');

const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '../../'));

exports.initialize = function (loaderConfig) {
	const instrumenter = iLibInstrument.createInstrumenter();
	loaderConfig.nodeInstrumenter = function (contents, source) {
		if (minimatch(source, '**/test/**')) {
			// tests don't get instrumented
			return contents;
		}
		// Try to find a .map file
		let map = undefined;
		try {
			map = JSON.parse(fs.readFileSync(`${source}.map`).toString());
		} catch (err) {
			// missing source map...
		}
		try {
			return instrumenter.instrumentSync(contents, source, map);
		} catch (e) {
			console.error(`Error instrumenting ${source}: ${e}`);
			throw e;
		}
	};
};

exports.createReport = function (isSingle, coveragePath, formats) {
	const mapStore = iLibSourceMaps.createSourceMapStore();
	const coverageMap = iLibCoverage.createCoverageMap(global.__coverage__);
	return mapStore.transformCoverage(coverageMap).then((transformed) => {
		// Paths come out all broken
		const newData = Object.create(null);
		Object.keys(transformed.data).forEach((file) => {
			const entry = transformed.data[file];
			const fixedPath = fixPath(entry.path);
			entry.data.path = fixedPath;
			newData[fixedPath] = entry;
		});
		transformed.data = newData;

		const context = iLibReport.createContext({
			dir: coveragePath || path.join(REPO_PATH, `.build/coverage${isSingle ? '-single' : ''}`),
			coverageMap: transformed
		});
		const tree = context.getTree('flat');

		const reports = [];
		if (formats) {
			if (typeof formats === 'string') {
				formats = [formats];
			}
			formats.forEach(format => {
				reports.push(iReports.create(format));
			});
		} else if (isSingle) {
			reports.push(iReports.create('lcovonly'));
		} else {
			reports.push(iReports.create('json'));
			reports.push(iReports.create('lcov'));
			reports.push(iReports.create('html'));
		}
		reports.forEach(report => tree.visit(report, context));
	});
};

function toUpperDriveLetter(str) {
	if (/^[a-z]:/.test(str)) {
		return str.charAt(0).toUpperCase() + str.substr(1);
	}
	return str;
}

function toLowerDriveLetter(str) {
	if (/^[A-Z]:/.test(str)) {
		return str.charAt(0).toLowerCase() + str.substr(1);
	}
	return str;
}

function fixPath(brokenPath) {
	const startIndex = brokenPath.lastIndexOf(REPO_PATH);
	if (startIndex === -1) {
		return toLowerDriveLetter(brokenPath);
	}
	return toLowerDriveLetter(brokenPath.substr(startIndex));
}
