import { homedir } from "node:os";
import { resolve } from "node:path";
import { parseArgs } from "node:util";
import { loadConfig, resolveConfigPath } from "./config.js";
import { Daemon } from "./daemon.js";
import { install, status, uninstall } from "./systemd.js";
import { Logger } from "./logger.js";
import { scanForProjects } from "./project-scanner.js";
import { syncSwarmRegistryFromProjects } from "./swarm-registry.js";

export const COMMAND_NAME = "sf-server";

export const USAGE = `Usage: sf-server [options]

Alias: sf-daemon

Options:
  --config <path>  Path to YAML config file (default: ~/.sf/daemon.yaml)
  --verbose        Lower log level to debug AND mirror entries to stderr
  --sync-swarms    One-shot SF server swarm registry refresh, then exit
                  Normal sf-server runs auto-sync by default; set swarms.auto_start=true
                  to also start missing clients during daemon sync
  --start <path>   Start an autonomous SF session for this project path
  --command <text> Command to send for --start (default: /sf autonomous)
  --install        Install the systemd user unit (auto-starts on login via systemd --user)
  --uninstall      Uninstall the systemd user unit
  --status         Show systemd user unit status (registered, PID, exit code)
  --help           Show this help message and exit
`;

export async function main(): Promise<void> {
	const { values } = parseArgs({
		options: {
			config: { type: "string", short: "c" },
			verbose: { type: "boolean", short: "v", default: false },
			"sync-swarms": { type: "boolean", default: false },
			start: { type: "string" },
			command: { type: "string" },
			install: { type: "boolean", default: false },
			uninstall: { type: "boolean", default: false },
			status: { type: "boolean", default: false },
			help: { type: "boolean", short: "h", default: false },
		},
		strict: true,
	});

	if (values.help) {
		process.stdout.write(USAGE);
		process.exit(0);
	}

	// --- systemd commands (dispatch before Daemon creation) ---

	if (values.install) {
		const configPath = resolveConfigPath(values.config);
		const scriptPath = resolve(import.meta.dirname, "cli.js");

		install({
			nodePath: process.execPath,
			scriptPath,
			configPath,
		});
		process.stdout.write(
			`${COMMAND_NAME}: systemd user unit installed and enabled.\n`,
		);
		process.exit(0);
	}

	if (values.uninstall) {
		uninstall();
		process.stdout.write(`${COMMAND_NAME}: systemd user unit uninstalled.\n`);
		process.exit(0);
	}

	if (values.status) {
		const result = status();
		if (!result.registered) {
			process.stdout.write(`${COMMAND_NAME}: not registered with systemd.\n`);
		} else if (result.pid != null) {
			process.stdout.write(
				`${COMMAND_NAME}: running (PID ${result.pid}, last exit status: ${result.lastExitStatus ?? "n/a"})\n`,
			);
		} else {
			process.stdout.write(
				`${COMMAND_NAME}: registered but not running (last exit status: ${result.lastExitStatus ?? "n/a"})\n`,
			);
		}
		process.exit(0);
	}

	// --- normal daemon start ---

	const configPath = resolveConfigPath(values.config);
	const config = loadConfig(configPath);

	// --verbose lowers log level to debug AND mirrors to stderr. Without
	// this, debug entries are dropped before reaching the verbose stderr
	// mirror — making --verbose silently useless on a default-info config.
	const logger = new Logger({
		filePath: config.log.file,
		level: values.verbose ? "debug" : config.log.level,
		verbose: values.verbose,
	});

	if (values["sync-swarms"]) {
		const projects = await scanForProjects(config.projects.scan_roots);
		const result = syncSwarmRegistryFromProjects(
			projects,
			config.swarms?.registry_path ?? resolve(homedir(), ".sf", "swarms.json"),
		);
		logger.info("swarm registry synced", {
			registry_path: result.registryPath,
			discovered: result.discovered,
			written: result.written,
		});
		process.stdout.write(
			`${COMMAND_NAME}: synced ${result.written} swarm row${result.written === 1 ? "" : "s"} to ${result.registryPath}\n`,
		);
		await logger.close();
		process.exit(0);
	}

	const daemon = new Daemon(config, logger);
	await daemon.start();

	if (values.start !== undefined) {
		const projectDir =
			values.start.trim() === "" ? process.cwd() : values.start;
		const sessionId = await daemon.getSessionManager().startSession({
			projectDir,
			...(values.command ? { command: values.command } : {}),
		});
		logger.info("batch session started", { sessionId, projectDir });
	}
}

export function handleFatalError(err: unknown): never {
	const msg = err instanceof Error ? err.message : String(err);
	process.stderr.write(`${COMMAND_NAME}: fatal: ${msg}\n`);
	process.exit(1);
}
