import { writeFileSync } from 'node:fs';
import { resolve } from 'node:path';

import { services as SERVICE_REGISTRY } from './services/registry';
import type { ServiceName } from './services/types';
import { createN8NStack, type N8NStack } from './stack';

export interface ServiceStackOptions {
	services: ServiceName[];
	projectName?: string;
}

/**
 * Creates a stack with only services (no n8n containers).
 * Useful for integration tests that need databases/services but not full n8n.
 *
 * @example
 * const stack = await createServiceStack({ services: ['postgres'] });
 * const pgContainer = stack.serviceResults.postgres?.container;
 * const host = pgContainer.getHost();
 * const port = pgContainer.getMappedPort(5432);
 * await stack.stop();
 */
export async function createServiceStack(options: ServiceStackOptions): Promise<N8NStack> {
	const { services, projectName } = options;

	return await createN8NStack({
		mains: 0,
		workers: 0,
		postgres: services.includes('postgres'),
		services,
		projectName,
		external: true,
	});
}

/**
 * Collects host-reachable env vars (mapped ports, localhost) for every service
 * in the stack. Used by `pnpm services` to produce the .env that `pnpm dev`
 * picks up.
 */
export function collectExternalEnv(
	stack: N8NStack,
	services: ServiceName[],
): Record<string, string> {
	const env: Record<string, string> = {};
	for (const name of services) {
		const result = stack.serviceResults[name];
		if (!result) continue;
		const service = SERVICE_REGISTRY[name];
		Object.assign(env, service.env?.(result, true) ?? {}, service.extraEnv?.(result, true) ?? {});
	}
	return env;
}

/**
 * Path to the .env file that `pnpm dev` / `pnpm start` reads. `pnpm start`
 * runs `os-normalize.mjs` which `cd`s into `packages/cli/bin` before launching
 * n8n, and dotenv loads from cwd.
 */
export function devEnvFilePath(): string {
	return resolve(__dirname, '../../..', 'packages/cli/bin/.env');
}

/**
 * Writes the dev-loop .env file consumed by `pnpm dev`. Returns the env vars
 * that were written so callers can log a summary.
 */
export function writeDevEnvFile(stack: N8NStack, services: ServiceName[]): Record<string, string> {
	const env = collectExternalEnv(stack, services);
	if (Object.keys(env).length === 0) return env;

	const lines = [
		'# Generated by pnpm services — do not edit',
		`# Project: ${stack.projectName}`,
		'# Stop with: pnpm --filter n8n-containers services:clean',
		'',
		...Object.entries(env).map(([key, value]) => `${key}=${value}`),
		'',
	];
	writeFileSync(devEnvFilePath(), lines.join('\n'));
	return env;
}
