import { createRequire } from 'node:module'
import path from 'node:path'
import { federation } from '@module-federation/vite'
import react from '@vitejs/plugin-react'
import type { InlineConfig } from 'vite'
import { discoverExposes } from '../lib/discover.ts'
import { resolveWorkflowsDeps } from '../plugins/resolve-workflows.ts'
import { generatePandaConfig } from './panda.ts'

const require = createRequire(import.meta.url)

export interface MFConfigOptions {
	/** Absolute path to the customer's workflows directory */
	workflowsDir: string
	/** Absolute path to the customer's project root */
	projectRoot: string
	/** Absolute path to this package's root (where node_modules lives) */
	packageRoot: string
	/** Federation name (derived from customer's package.json name) */
	federationName: string
	/** Output directory for the MF remote build */
	outDir: string
}

/**
 * Creates a Vite config for the Module Federation production build.
 *
 * This produces a remoteEntry.js that the main Pyck web app loads at runtime.
 * Workflow React components are exposed as MF modules.
 */
export function createMFConfig(opts: MFConfigOptions): {
	config: InlineConfig
	cleanup: () => void
} {
	const { workflowsDir, projectRoot, packageRoot, federationName, outDir } = opts

	const resolveAnchor = path.join(projectRoot, '__resolve_anchor__.ts')
	const exposes = discoverExposes(workflowsDir)

	// PandaCSS is needed because workflow components use @pyck/styled-system utilities.
	const panda = generatePandaConfig({ appDir: projectRoot, workflowsDir, packageRoot })

	const installRoot = packageRoot.replace(/\/node_modules\/.*$/, '')

	const config: InlineConfig = {
		root: projectRoot,
		base: process.env.MF_PUBLIC_PATH || '/',

		plugins: [
			react(),
			resolveWorkflowsDeps(resolveAnchor),
			federation({
				name: federationName,
				filename: 'remoteEntry.js',
				dts: false,
				manifest: true,
				exposes,
				shared: {
					react: { singleton: true, import: false },
					'react-dom': { singleton: true, import: false },
				},
			}),
			{
				name: 'pyck-panda-css',
				async buildStart() {
					const { loadConfigAndCreateContext } = require('@pandacss/node')
					const ctx = await loadConfigAndCreateContext({
						configPath: panda.configPath,
						cwd: installRoot,
					})
					const sheet = ctx.createSheet()
					ctx.appendBaselineCss(sheet)
					ctx.parseFiles()
					ctx.appendParserCss(sheet)
					// MF build doesn't have index.css, so we write to projectRoot
					const css = sheet.toCss()
					const outPath = path.join(projectRoot, '__panda.css')
					const fs = await import('node:fs')
					fs.writeFileSync(outPath, css, 'utf-8')
				},
			},
		],

		build: {
			outDir: path.resolve(projectRoot, outDir),
			target: 'esnext',
			emptyOutDir: true,
			rollupOptions: {
				input: {},
			},
		},
	}

	return { config, cleanup: panda.cleanup }
}
