import createTempFile from 'tempfile';
import { ConventionalChangelog } from 'conventional-changelog';
import { resolve } from 'path';
import { createReadStream, createWriteStream } from 'fs';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { pipeline } from 'stream/promises';
import packageJson from '../../package.json' with { type: 'json' };

const baseDir = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
const fullChangelogFile = resolve(baseDir, 'CHANGELOG.md');
// Version includes experimental versions (e.g., 1.2.3-exp.g123abcgg)
const versionChangelogFile = resolve(baseDir, `CHANGELOG-${packageJson.version}.md`);

const changelogStream = new ConventionalChangelog()
	.package(packageJson)
	.readRepository()
	.loadPreset('angular')
	.tags({
		prefix: 'n8n@',
	})
	.context({
		version: packageJson.version,
		repoUrl: 'https://github.com/n8n-io/n8n',
	})
	.options({
		releaseCount: 1,
		transformCommit(commit) {
			const hasNoChangelogInHeader = commit.header?.includes('(no-changelog)');
			const isBenchmarkScope = commit.scope === 'benchmark';

			// Ignore commits that have 'benchmark' scope or '(no-changelog)' in the header
			if (hasNoChangelogInHeader || isBenchmarkScope) return null;

			// Strip backport information from commit subject, e.g.:
			// "Fix something (backport to release-candidate/2.12.x) (#123)" → "Fix something (#123)"
			if (commit.subject) {
				// The commit.subject is immutable so we need to recreate the commit object

				/** @type { import("conventional-changelog").Commit } */
				let newCommit = /** @type { any } */ ({
					...commit,
					subject: commit.subject.replace(/\s*\(backport to [^)]+\)/g, ''),
				});

				return newCommit;
			}

			return commit;
		},
	})
	.writeStream()
	.on('error', (err) => {
		console.error(err.stack);
		process.exit(1);
	});

// Write the new changelog to a new temporary file, so that the contents can be used in the PR description
await pipeline(changelogStream, createWriteStream(versionChangelogFile));

// Since we can't read and write from the same file at the same time,
// we use a temporary file to output the updated changelog to.
const tmpFile = createTempFile();
const tmpStream = createWriteStream(tmpFile);
await pipeline(createReadStream(versionChangelogFile), tmpStream, { end: false });
tmpStream.write('\n\n');
await pipeline(createReadStream(fullChangelogFile), tmpStream);
await pipeline(createReadStream(tmpFile), createWriteStream(fullChangelogFile));
