/**
 * Vite Configuration for Shared FlowDrop Library
 *
 * Builds an ES module with code splitting for use in Drupal.
 * Heavy optional features (CodeMirror, EasyMDE) are split into
 * separate chunks that are lazy-loaded via dynamic import().
 *
 * Output:
 *   build/flowdrop.es.js       — main entry chunk
 *   build/flowdrop-*.js        — lazy-loaded chunks (code editors, markdown editor)
 *   build/flowdrop.css         — bundled styles
 *
 * Global: window.FlowDrop (assigned by main.ts entry wrapper)
 */

import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import path from "path";
import fs from "fs";
import type { Plugin } from "vite";

const flowdropPkg = JSON.parse(
	fs.readFileSync(
		path.resolve("./node_modules/@flowdrop/flowdrop/package.json"),
		"utf-8"
	)
);
const flowdropVersion = flowdropPkg.version;

/**
 * Rollup plugin that appends ?v=<version> to all inter-chunk import paths.
 *
 * Drupal's asset system adds ?v=<version> to the entry script URL, but
 * dynamic import() paths inside chunks are bare (e.g. "./flowdrop.es.js").
 * The browser treats "flowdrop.es.js?v=0.0.59" and "flowdrop.es.js" as
 * different module URLs, causing a duplicate fetch of the main bundle.
 *
 * This plugin rewrites relative .js imports in every output chunk so that
 * all inter-chunk references carry the same version query string Drupal uses.
 */
function chunkVersionPlugin(): Plugin {
	const suffix = `?v=${flowdropVersion}`;
	return {
		name: "flowdrop-chunk-version",
		renderChunk(code) {
			// Match all inter-chunk import forms:
			//   from "./flowdrop-foo.js"       — static named import
			//   import("./flowdrop-foo.js")     — dynamic import
			//   import "./flowdrop-foo.js"      — bare side-effect import
			const rewritten = code.replace(
				/(["'])(\.\/flowdrop[^"']*\.js)\1/g,
				(_match, quote, path) => `${quote}${path}${suffix}${quote}`
			);
			if (rewritten !== code) {
				return { code: rewritten, map: null };
			}
			return null;
		}
	};
}

/**
 * Rollup plugin that redirects imports of the full FormField component
 * (which statically bundles CodeMirror) to the light/registry-based version.
 * This allows CodeMirror to be lazy-loaded as a separate chunk.
 *
 * Uses this.resolve() to catch ANY import path that resolves to
 * FormField.svelte (e.g., './FormField.svelte', '../components/form/FormField.svelte')
 * so that `export * from "@flowdrop/flowdrop/form"` is safe — the FormFieldFull
 * re-export gets redirected to FormFieldLight automatically.
 */
function formFieldLightPlugin(): Plugin {
	const fullFormField = path.resolve(
		"./node_modules/@flowdrop/flowdrop/dist/components/form/FormField.svelte"
	);
	const lightFormField = path.resolve(
		"./node_modules/@flowdrop/flowdrop/dist/components/form/FormFieldLight.svelte"
	);

	return {
		name: "flowdrop-formfield-light",
		enforce: "pre",
		async resolveId(source, importer, options) {
			if (!importer) return null;

			// Only intercept imports from within @flowdrop/flowdrop
			if (!importer.includes("@flowdrop/flowdrop")) return null;

			// Quick filter: skip anything that clearly isn't FormField-related
			if (!source.includes("FormField") && !source.endsWith("FormField.svelte")) return null;

			// Skip if already pointing to the light version
			if (source.includes("FormFieldLight")) return null;

			// Resolve the import to its absolute path, then check if it's
			// the heavy FormField.svelte that pulls in CodeMirror
			const resolved = await this.resolve(source, importer, { ...options, skipSelf: true });
			if (resolved && resolved.id === fullFormField) {
				return lightFormField;
			}

			return null;
		}
	};
}

export default defineConfig({
	plugins: [
		chunkVersionPlugin(),
		formFieldLightPlugin(),
		svelte({
			compilerOptions: {
				dev: false
			},
			onwarn: (warning, handler) => {
				if (warning.filename?.includes("node_modules")) {
					return;
				}
				handler(warning);
			}
		})
	],
	resolve: {
		alias: {
			$lib: path.resolve("./src/lib"),
			"$app/stores": path.resolve("./src/lib/mocks/app-stores.js"),
			"$app/forms": path.resolve("./src/lib/mocks/app-forms.js"),
			"$app/navigation": path.resolve("./src/lib/mocks/app-navigation.js"),
			"$app/environment": path.resolve("./src/lib/mocks/app-environment.js"),
			// Alias for internal @flowdrop/flowdrop dist paths, bypassing the
			// package.json exports restriction. This allows importing settings/theme
			// without going through the main entry (which pulls in FormFieldFull → CodeMirror).
			"flowdrop-internal": path.resolve("./node_modules/@flowdrop/flowdrop/dist")
		},
		conditions: ["svelte", "browser", "import"],
		dedupe: ["svelte"]
	},
	build: {
		// Disable Vite's module preload injection. The preload helper resolves
		// chunk URLs from the site root ("/flowdrop-full.js") which 404s in
		// Drupal where files live under /modules/.../build/. The actual
		// dynamic import() paths resolve correctly relative to the module URL.
		modulePreload: false,
		outDir: "build",
		rollupOptions: {
			input: "src/lib/main.ts",
			output: {
				format: "es",
				entryFileNames: "flowdrop.es.js",
				chunkFileNames(chunkInfo) {
					// Rename chunks to stable, predictable names.
					// Drupal libraries.yml references these by name, so they
					// must be deterministic across builds.
					const ids = chunkInfo.moduleIds ?? [];
					if (ids.some((id) => id.includes("/editor/index."))) {
						return "flowdrop-editor.js";
					}
					if (ids.some((id) => id.includes("/playground/index."))) {
						return "flowdrop-playground.js";
					}
					if (ids.some((id) => id.includes("/form/code"))) {
						return "flowdrop-code.js";
					}
					if (ids.some((id) => id.includes("/form/markdown"))) {
						return "flowdrop-markdown.js";
					}
					if (ids.some((id) => id.includes("/form/full"))) {
						return "flowdrop-form-full.js";
					}
					// Normalize PascalCase/camelCase names to kebab-case.
					const name = chunkInfo.name
						.replace(/([a-z])([A-Z])/g, "$1-$2")
						.replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
						.toLowerCase();
					return `flowdrop-${name}.js`;
				},
				assetFileNames: (assetInfo) => {
					if (assetInfo.name?.endsWith(".css")) {
						return "flowdrop.css";
					}
					return assetInfo.name || "assets/[name]-[hash][extname]";
				}
			}
		},
		// Keep all CSS in a single file — Drupal loads CSS via libraries.yml,
		// and dynamic JS chunks don't need separate CSS loading.
		cssCodeSplit: false,
		sourcemap: true,
		minify: "terser",
		terserOptions: {
			compress: {
				drop_debugger: true,
				pure_funcs: ['console.log', 'console.debug', 'console.info']
			}
		},
		target: "es2020",
		chunkSizeWarningLimit: 5000,
		commonjsOptions: {
			include: [/node_modules/],
			transformMixedEsModules: true
		}
	},
	define: {
		"process.env.NODE_ENV": JSON.stringify("production"),
		"process.env": "{}",
		"import.meta.env.MODE": JSON.stringify("production"),
		"import.meta.env.DEV": "false",
		"import.meta.env.PROD": "true",
		"import.meta.env.SSR": "false"
	},
	envPrefix: "__FLOWDROP_DISABLED__",
	optimizeDeps: {
		include: [
			"@flowdrop/flowdrop",
			"svelte",
			"@xyflow/svelte",
			"@iconify/svelte",
			"uuid"
		],
		exclude: []
	}
});
