import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import fs from "fs";
import path from "path";

const banner =
	`/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;

/**
 * Automatically generates the predefinedTemplates.ts file by scanning the templates directory.
 */
const generateTemplatesIndex = () => {
	const templatesDir = "./templates";
	const outputFile = "./constants/predefinedTemplates.ts";

	const predefinedDir = path.join(templatesDir, "predefined");

	if (!fs.existsSync(templatesDir)) return;
	if (!fs.existsSync(predefinedDir)) {
		fs.mkdirSync(predefinedDir, { recursive: true });
	}

	const predefinedTemplates = [];
	const communityTemplates = [];

	// Read predefined templates
	const predefinedFiles = fs.readdirSync(predefinedDir);
	predefinedFiles.forEach((file) => {
		if (file.endsWith(".json")) {
			const filePath = path.join(predefinedDir, file);
			const content = JSON.parse(fs.readFileSync(filePath, "utf8"));
			content.isPredefined = true;
			predefinedTemplates.push(content);
		}
	});

	// Read community templates
	const rootFiles = fs.readdirSync(templatesDir);
	rootFiles.forEach((file) => {
		if (file.endsWith(".json")) {
			const filePath = path.join(templatesDir, file);
			const content = JSON.parse(fs.readFileSync(filePath, "utf8"));
			content.isPredefined = false;
			communityTemplates.push(content);
		}
	});

	const content = `/**
 * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT MANUALLY.
 * To add a new predefined template, create a JSON file in the /templates/predefined directory.
 * To add a community template, create a JSON file in the /templates directory.
 */
import { StatusTemplate } from "types/pluginSettings";

export const PREDEFINED_TEMPLATES: StatusTemplate[] = ${JSON.stringify(predefinedTemplates, null, "\t")};
export const COMMUNITY_TEMPLATES: StatusTemplate[] = ${JSON.stringify(communityTemplates, null, "\t")};
`;

	fs.writeFileSync(outputFile, content);
	console.log(
		`\x1b[36m[Templates]\x1b[0m Automatically registered ${predefinedTemplates.length} predefined and ${communityTemplates.length} community templates.`,
	);
};

// Generate templates index before build
generateTemplatesIndex();

const prod = process.argv[2] === "production";

// CSS bundling function
const buildStyles = async () => {
	await esbuild.build({
		entryPoints: ["styles/index.css"],
		bundle: true,
		outfile: "styles.css",
		minify: prod,
		logLevel: "info",
	});
};

const context = await esbuild.context({
	banner: {
		js: banner,
	},
	entryPoints: ["main.tsx"],
	bundle: true,
	external: [
		"obsidian",
		"electron",
		"@codemirror/autocomplete",
		"@codemirror/collab",
		"@codemirror/commands",
		"@codemirror/language",
		"@codemirror/lint",
		"@codemirror/search",
		"@codemirror/state",
		"@codemirror/view",
		"@lezer/common",
		"@lezer/highlight",
		"@lezer/lr",
		...builtins
	],
	format: "cjs",
	target: "es2018",
	logLevel: "info",
	sourcemap: prod ? false : "inline",
	treeShaking: true,
	outfile: "main.js",
	minify: prod,
	jsx: "transform",
	jsxFactory: "React.createElement",
	jsxFragment: "React.Fragment",
});

// CSS context for watch mode
const cssContext = await esbuild.context({
	entryPoints: ["styles/index.css"],
	bundle: true,
	outfile: "styles.css",
	minify: prod,
	logLevel: "info",
});

if (prod) {
	await context.rebuild();
	await buildStyles(); // Build CSS in production mode
	process.exit(0);
} else {
	await context.watch();
	await cssContext.watch(); // Watch CSS files in development mode
}