import { n as colors } from "../diagnostics-reporter-CBBZwoMv.mjs";
import { createBuild } from "./build.mjs";
import { n as resolveDevServerPort, t as createDevServer } from "../dev-Cv43GfqM.mjs";
import process from "node:process";
import cac from "cac";
import { safeParse } from "valibot";
//#region src/adapters/flags.ts
/**
* Identity helper that preserves the literal schema-map type — use this
* so `InferCliFlags<typeof myFlags>` resolves to the right object shape.
*
* ```ts
* const appFlags = defineCliFlags({
*   depth: v.pipe(v.number(), v.integer()),
*   config: v.optional(v.string()),
* })
*
* defineDevframe({
*   cli: { flags: appFlags },
*   setup(ctx, info) {
*     const flags = info.flags as InferCliFlags<typeof appFlags>
*     flags.depth // number
*     flags.config // string | undefined
*   },
* })
* ```
*/
function defineCliFlags(flags) {
	return flags;
}
/**
* Best-effort probe of a valibot schema to decide whether the
* corresponding CAC option takes a value. Unwraps `optional` / `nullable`
* / `nullish` / `default` / `pipe` wrappers then matches on the inner
* type's kind.
*/
function getSchemaKind(schema) {
	let current = schema;
	while (current) {
		const kind = current.type;
		if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") {
			current = current.wrapped ?? current.inner;
			continue;
		}
		if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) {
			current = current.pipe[0];
			continue;
		}
		return kind;
	}
	return "unknown";
}
/** Whether the CAC option for this schema should be a boolean flag. */
function isBooleanFlag(schema) {
	return getSchemaKind(schema) === "boolean";
}
/** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */
function parseCliFlags(schema, raw) {
	const flags = {};
	const issues = [];
	for (const [key, fieldSchema] of Object.entries(schema)) {
		const result = safeParse(fieldSchema, raw[key]);
		if (result.success) flags[key] = result.output;
		else issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`);
	}
	for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value;
	return issues.length ? {
		flags,
		issues
	} : { flags };
}
function toKebab(camel) {
	return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
}
/** Kebab-case a schema key for CAC option registration. */
function flagKeyToOption(camel) {
	return toKebab(camel);
}
//#endregion
//#region src/adapters/cli.ts
function createCli(d, options = {}) {
	const defaultPort = options.defaultPort ?? d.cli?.port ?? 9999;
	const defaultHost = d.cli?.host ?? "localhost";
	const cli = cac(d.cli?.command ?? d.id);
	const devCommand = cli.command("[...args]", "Start a local dev server").option("--port <port>", "Port to listen on").option("--host <host>", "Host to bind to", { default: defaultHost }).option("--open", "Open the browser on start").option("--no-open", "Do not open the browser");
	if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) {
		const optionName = flagKeyToOption(key);
		const description = schema.description ?? "";
		if (isBooleanFlag(schema)) devCommand.option(`--${optionName}`, description);
		else devCommand.option(`--${optionName} <value>`, description);
	}
	devCommand.action(async (_args, rawFlags) => {
		const flags = resolveTypedFlags(d, rawFlags);
		const host = flags.host ?? defaultHost;
		await createDevServer(d, {
			host,
			port: flags.port ?? await resolveDevServerPort(d, {
				host,
				defaultPort
			}),
			flags,
			onReady: options.onReady
		});
	});
	cli.command("build", "Build a self-contained static deploy of the devframe").option("--out-dir <outDir>", "Output directory", { default: "dist-static" }).option("--base <base>", "URL base", { default: "/" }).option("--pretty", "Pretty-print dump JSON (larger on disk)").action(async (flags) => {
		await createBuild(d, {
			outDir: flags.outDir,
			base: flags.base,
			pretty: flags.pretty
		});
	});
	cli.command("mcp", "Start an MCP server exposing agent-facing tools (stdio) [experimental]").action(async () => {
		const { createMcpServer } = await import("./mcp.mjs");
		await createMcpServer(d, {
			transport: "stdio",
			onReady: ({ transport }) => {
				console.error(`[devframe] "${d.id}" MCP server ready (${transport})`);
			}
		});
	});
	d.cli?.configure?.(cli);
	options.configureCli?.(cli);
	cli.help();
	cli.version("0.0.0");
	return {
		cli,
		async parse(argv = process.argv) {
			cli.parse(argv, { run: false });
			await cli.runMatchedCommand();
		}
	};
}
function resolveTypedFlags(d, raw) {
	if (!d.cli?.flags) return raw;
	const { flags, issues } = parseCliFlags(d.cli.flags, raw);
	if (issues?.length) {
		for (const issue of issues) console.error(colors.red`[devframe] invalid flag — ${issue}`);
		process.exit(1);
	}
	return flags;
}
//#endregion
export { createCli, defineCliFlags, parseCliFlags };
