import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const BUNDLE_CONFIG_PATH = fileURLToPath(new URL("../config/lsp.json", import.meta.url));
const TYPESCRIPT_SERVER_ID = "typescript-language-server";

interface LspConfigFile {
	version?: number;
	servers?: Array<{
		id?: string;
		bin?: string;
		args?: string[];
		[key: string]: unknown;
	}>;
}

export interface TypeScriptLspRuntime {
	nodeBinary: string;
	serverCliPath: string;
}

export function materializeBundleLspConfig(source: string, runtime: TypeScriptLspRuntime): string {
	const config = JSON.parse(source) as LspConfigFile;
	const server = config.servers?.find((entry) => entry.id === TYPESCRIPT_SERVER_ID);
	if (server === undefined) {
		throw new Error(`Missing ${TYPESCRIPT_SERVER_ID} entry in bundled LSP config`);
	}

	server.bin = runtime.nodeBinary;
	server.args = [runtime.serverCliPath, "--stdio"];
	return `${JSON.stringify(config, null, 2)}\n`;
}

export function deployBundleLspConfig(agentDir: string, runtime: TypeScriptLspRuntime): void {
	const targetPath = join(agentDir, "lsp.json");
	const bundledConfig = materializeBundleLspConfig(readFileSync(BUNDLE_CONFIG_PATH, "utf8"), runtime);

	try {
		if (readFileSync(targetPath, "utf8") === bundledConfig) return;
	} catch {
		// Missing or unreadable target: replace it with the bundle-owned baseline.
	}

	mkdirSync(dirname(targetPath), { recursive: true });
	const temporaryPath = `${targetPath}.my-pi.tmp`;
	writeFileSync(temporaryPath, bundledConfig, "utf8");
	renameSync(temporaryPath, targetPath);
}
