import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

type Replacement = {
	file: string;
	pattern: string;
	replacement: string;
};

type PatchResult = {
	file: string;
	updated: boolean;
	replacements: number;
};

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, "..", "..");
const targetRoot = path.resolve(
	repoRoot,
	process.argv[2] ?? process.env.MONKEY_PATCH_TARGET ?? "frontend-backup"
);

const chunkFrom = "4.CrDfIbdR.js";
const chunkTo = "4.DB4WphWP.js";

const replacements: Replacement[] = [
	{
		file: path.join(targetRoot, "_app", "immutable", "entry", "app.DTM8GXam.js"),
		pattern: `../nodes/${chunkFrom}`,
		replacement: `../nodes/${chunkTo}`,
	},
	{
		file: path.join(targetRoot, "service-worker.js"),
		pattern: `/_app/immutable/nodes/${chunkFrom}`,
		replacement: `/_app/immutable/nodes/${chunkTo}`,
	},
	{
		file: path.join(targetRoot, "index.html"),
		pattern: `/_app/immutable/nodes/${chunkFrom}`,
		replacement: `/_app/immutable/nodes/${chunkTo}`,
	},
];

async function ensureChunkExists(fileName: string) {
	const chunkPath = path.join(targetRoot, "_app", "immutable", "nodes", fileName);
	await fs.access(chunkPath);
}

async function applyReplacement({ file, pattern, replacement }: Replacement): Promise<PatchResult> {
	const contents = await fs.readFile(file, "utf8");
	const occurrences = contents.split(pattern).length - 1;

	if (occurrences === 0) {
		if (contents.includes(replacement)) {
			return { file, updated: false, replacements: 0 };
		}
		throw new Error(`Pattern "${pattern}" not found in ${path.relative(repoRoot, file)}`);
	}

	const updatedContents = contents.replaceAll(pattern, replacement);
	await fs.writeFile(file, updatedContents);

	return { file, updated: true, replacements: occurrences };
}

async function main() {
	await ensureChunkExists(chunkFrom);
	await ensureChunkExists(chunkTo);

	const results: PatchResult[] = [];

	for (const replacement of replacements) {
		const result = await applyReplacement(replacement);
		results.push(result);
	}

	for (const result of results) {
		const relative = path.relative(repoRoot, result.file);
		if (!result.updated) {
			console.info(`✔ ${relative} already points to ${chunkTo}`);
		} else {
			console.info(`✔ Updated ${relative} (${result.replacements} replacement${result.replacements === 1 ? "" : "s"})`);
		}
	}

	console.info("Modal chunk now rerouted to", chunkTo);
}

main().catch(error => {
	console.error(error instanceof Error ? error.message : error);
	process.exitCode = 1;
});
