import { spawn } from "node:child_process";
import { createLogger } from "../logger/logger.controller.js";
import { emitToRoom } from "../socket.io/roomEmitter.socket.js";
import { updateAppStats } from "./updateAppStats.utils.js";
import { getAppVersion } from "./version.utils.js";
import { zipBuild } from "./zipper.utils.js";

export const emitBuildLog = (message: string, level = "info") => {
	const payload = {
		type: "build",
		level,
		message,
		timestamp: new Date().toISOString(),
	};

	//console.log(`[BUILD][${level.toUpperCase()}] ${message}`);

	emitToRoom("admin:build", payload as any);
	if (payload.level === "info") {
		log.info({ stack: payload }, payload.message);
	}

	// if (log) {
	// 	log(payload);
	// }
};

export let building = false;
const log = createLogger({ module: "utils", subModule: "builds" });
export const build = async () => {
	const appDir = process.env.DEV_DIR ?? "";
	const build = await getAppVersion();

	return new Promise((resolve) => {
		building = true;

		updateAppStats({
			lastUpdated: new Date(),
			building: true,
		});

		emitBuildLog(`Starting build in: ${appDir}`);

		const child = spawn("npm", ["run", "build"], {
			cwd: appDir,
			shell: true,
		});

		child.stdout.on("data", (data) => {
			const lines = data.toString().split(/\r?\n/);
			for (const line of lines) {
				if (line.trim() !== "") {
					emitBuildLog(line, "info");
				}
			}
		});

		child.stderr.on("data", (data) => {
			const lines = data.toString().split(/\r?\n/);
			for (const line of lines) {
				if (line.trim() !== "") {
					emitBuildLog(line, "error");
				}
			}
		});

		child.on("close", (code) => {
			if (code === 0) {
				emitBuildLog("Build completed successfully.", "info");
				building = false;
				zipBuild();
				resolve(true);
			} else {
				building = false;
				updateAppStats({
					lastUpdated: new Date(),
					building: false,
					currentBuild: build.build,
				});
				emitBuildLog(`Build failed with code ${code}`, "error");
				//reject(new Error(`Build failed with code ${code}`));
			}
		});

		child.on("error", (err) => {
			building = false;
			updateAppStats({
				lastUpdated: new Date(),
				building: false,
			});
			emitBuildLog(`Process error: ${err.message}`, "error");
			// reject(err);
		});
	});
};
