import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";

const repoRoot = process.cwd();
const packageName = process.argv[2] || "userfront";
const lcovPath = path.join(repoRoot, packageName, "coverage", "lcov.info");
const reportsDir = path.join(repoRoot, "reports");

const excludedSourceFiles = new Set(["lib/main.dart", "lib/i18n_data.dart"]);

function normalizeSourcePath(sourcePath) {
	const normalized = sourcePath.replace(/\\/g, "/");
	const packagePrefix = `${packageName}/`;
	return normalized.startsWith(packagePrefix)
		? normalized.slice(packagePrefix.length)
		: normalized;
}

function shouldExcludeSource(sourcePath) {
	const normalized = normalizeSourcePath(sourcePath);
	return (
		excludedSourceFiles.has(normalized) ||
		normalized.endsWith(".g.dart") ||
		normalized.endsWith(".freezed.dart")
	);
}

function parseLcov(raw) {
	const records = [];
	let current = null;

	for (const line of raw.split(/\r?\n/)) {
		if (line.startsWith("SF:")) {
			current = { sourceFile: normalizeSourcePath(line.slice(3)), lines: [] };
			continue;
		}

		if (!current) continue;

		if (line.startsWith("DA:")) {
			const [, hitsValue] = line.slice(3).split(",");
			const hits = Number(hitsValue);
			current.lines.push(Number.isFinite(hits) ? hits : 0);
			continue;
		}

		if (line === "end_of_record") {
			records.push(current);
			current = null;
		}
	}

	if (current) {
		records.push(current);
	}

	return records;
}

function formatPct(value) {
	return `${value.toFixed(2)}%`;
}

function renderMarkdown(row) {
	return [
		"# Userfront Flutter Coverage Summary",
		"",
		"| Package | Lines | Covered / Total | LCOV |",
		"| --- | ---: | ---: | --- |",
		`| ${row.package} | ${formatPct(row.lines)} | ${row.coveredLines} / ${row.totalLines} | ${row.lcovPath} |`,
		"",
		"Coverage excludes Flutter bootstrap/generated files: `lib/main.dart`, `lib/i18n_data.dart`, `*.g.dart`, `*.freezed.dart`.",
		"",
	].join("\n");
}

const lcov = await readFile(lcovPath, "utf8");
const includedRecords = parseLcov(lcov).filter(
	(record) => !shouldExcludeSource(record.sourceFile),
);

const totalLines = includedRecords.reduce(
	(total, record) => total + record.lines.length,
	0,
);
const coveredLines = includedRecords.reduce(
	(total, record) => total + record.lines.filter((hits) => hits > 0).length,
	0,
);
const lineCoverage = totalLines === 0 ? 0 : (coveredLines / totalLines) * 100;

const row = {
	package: packageName,
	statements: lineCoverage,
	branches: null,
	functions: null,
	lines: lineCoverage,
	coveredLines,
	totalLines,
	summaryPath: "reports/package-coverage-summary.json",
	htmlPath: null,
	lcovPath: `${packageName}/coverage/lcov.info`,
};

await mkdir(reportsDir, { recursive: true });
await writeFile(
	path.join(reportsDir, "package-coverage-summary.json"),
	`${JSON.stringify({ packages: [row] }, null, 2)}\n`,
);
await writeFile(
	path.join(reportsDir, `${packageName}-coverage-summary.md`),
	renderMarkdown(row),
);

console.log(renderMarkdown(row));
