import * as fs from "node:fs/promises";
import * as path from "node:path";
import { $ } from "execa";
import type { ReleaseOpts } from "./main";
import {
	copyReleasesPath,
	deleteReleasesPath,
	fetchGitRef,
	listReleasesObjects,
	PREFIX,
	uploadContentToReleases,
	versionOrCommitToRef,
} from "./utils";

export async function promoteArtifacts(opts: ReleaseOpts) {
	// Determine which commit to use for source artifacts
	let sourceCommit = opts.commit;
	if (opts.reuseEngineVersion) {
		console.log(`==> Reusing artifacts from ${opts.reuseEngineVersion}`);
		const ref = versionOrCommitToRef(opts.reuseEngineVersion);
		await fetchGitRef(ref);
		const result = await $`git rev-parse ${ref}`;
		sourceCommit = result.stdout.trim().slice(0, 7);
		console.log(`==> Source commit: ${sourceCommit}`);
	}

	// Promote TypeScript SDK artifacts (uploaded by build-artifacts.ts to sandbox-agent/{commit}/typescript/)
	await promotePath(opts, sourceCommit, "typescript");

	// Promote binary artifacts (uploaded by CI in release.yaml to sandbox-agent/{commit}/binaries/)
	await promotePath(opts, sourceCommit, "binaries");

	// Upload install scripts
	await uploadInstallScripts(opts, opts.version);
	if (opts.latest) {
		await uploadInstallScripts(opts, "latest");
		await uploadInstallScripts(opts, opts.minorVersionChannel);
	}

	// Upload gigacode install scripts
	await uploadGigacodeInstallScripts(opts, opts.version);
	if (opts.latest) {
		await uploadGigacodeInstallScripts(opts, "latest");
	}
}


async function uploadInstallScripts(opts: ReleaseOpts, version: string) {
	const installScriptPaths = [
		path.resolve(opts.root, "scripts/release/static/install.sh"),
		path.resolve(opts.root, "scripts/release/static/install.ps1"),
	];

	for (const scriptPath of installScriptPaths) {
		let scriptContent = await fs.readFile(scriptPath, "utf-8");
		scriptContent = scriptContent.replace(/__VERSION__/g, version);

		const uploadKey = `${PREFIX}/${version}/${scriptPath.split("/").pop() ?? ""}`;

		console.log(`Uploading install script: ${uploadKey}`);
		await uploadContentToReleases(scriptContent, uploadKey);
	}
}

async function uploadGigacodeInstallScripts(opts: ReleaseOpts, version: string) {
	const installScriptPaths = [
		path.resolve(opts.root, "scripts/release/static/gigacode-install.sh"),
		path.resolve(opts.root, "scripts/release/static/gigacode-install.ps1"),
	];

	for (const scriptPath of installScriptPaths) {
		let scriptContent = await fs.readFile(scriptPath, "utf-8");
		scriptContent = scriptContent.replace(/__VERSION__/g, version);

		const uploadKey = `${PREFIX}/${version}/${scriptPath.split("/").pop() ?? ""}`;

		console.log(`Uploading gigacode install script: ${uploadKey}`);
		await uploadContentToReleases(scriptContent, uploadKey);
	}
}

async function copyPath(sourcePrefix: string, targetPrefix: string) {
	console.log(`Copying ${sourcePrefix} -> ${targetPrefix}`);
	await deleteReleasesPath(targetPrefix);
	await copyReleasesPath(sourcePrefix, targetPrefix);
}

/** S3-to-S3 copy from sandbox-agent/{commit}/{name}/ to sandbox-agent/{version}/{name}/ */
async function promotePath(opts: ReleaseOpts, sourceCommit: string, name: string) {
	console.log(`==> Promoting ${name} artifacts`);

	const sourcePrefix = `${PREFIX}/${sourceCommit}/${name}/`;
	const commitFiles = await listReleasesObjects(sourcePrefix);
	if (!Array.isArray(commitFiles?.Contents) || commitFiles.Contents.length === 0) {
		throw new Error(`No files found under ${sourcePrefix}`);
	}

	await copyPath(sourcePrefix, `${PREFIX}/${opts.version}/${name}/`);
	if (opts.latest) {
		await copyPath(sourcePrefix, `${PREFIX}/latest/${name}/`);
		if (name === "binaries") {
			const binariesSourcePrefix = `${PREFIX}/${sourceCommit}/binaries/sandbox-agent-`;
			const sandboxAgentBinaries = await listReleasesObjects(binariesSourcePrefix);
			if (
				!Array.isArray(sandboxAgentBinaries?.Contents) ||
				sandboxAgentBinaries.Contents.length === 0
			) {
				throw new Error(`No sandbox-agent binaries found under ${binariesSourcePrefix}`);
			}

			await copyPath(
				binariesSourcePrefix,
				`${PREFIX}/${opts.minorVersionChannel}/binaries/sandbox-agent-`,
			);
			return;
		}

		await copyPath(sourcePrefix, `${PREFIX}/${opts.minorVersionChannel}/${name}/`);
	}
}
