/**
 * OpenAPI spec generator — orchestrates all domain path registrations.
 *
 * Run:  pnpm swagger:generate
 *       (uses tsx so NodeNext ESM paths resolve correctly without a dist build)
 *
 * Rules:
 *  - NEVER import from #services, #models, #providers (no server runtime)
 *  - Only imports from src/contracts/ and @asteasolutions/zod-to-openapi
 *
 * Auto-discovery: Automatically imports all paths.ts files from src/contracts/
 */
import { OpenAPIRegistry, OpenApiGeneratorV3 } from '@asteasolutions/zod-to-openapi';
import { writeFileSync, mkdirSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import { readdirSync } from 'fs';

// ---------------------------------------------------------------------------
// Bootstrap
// ---------------------------------------------------------------------------
const __dirname = dirname(fileURLToPath(import.meta.url));
const PROJECT_ROOT = join(__dirname, '..', '..', '..');
const OUTPUT_DIR = join(PROJECT_ROOT, 'storage', 'swagger');
const OUTPUT_FILE = join(OUTPUT_DIR, 'openapi.json');
const CONTRACTS_DIR = join(PROJECT_ROOT, 'src', 'contracts');

const registry = new OpenAPIRegistry();

// Security scheme — used by auth-protected routes
registry.registerComponent('securitySchemes', 'BearerAuth', {
	type: 'http',
	scheme: 'bearer',
	bearerFormat: 'JWT',
});

// Auto-discover and register all domain paths
async function registerAllPaths() {
	const domains = readdirSync(CONTRACTS_DIR, { withFileTypes: true })
		.filter((dirent) => dirent.isDirectory())
		.map((dirent) => dirent.name);

	for (const domain of domains) {
		const pathsPath = join(CONTRACTS_DIR, domain, 'paths.ts');
		try {
			const module = await import(pathToFileURL(pathsPath).href);
			const registerFn = Object.values(module).find(
				(fn) => typeof fn === 'function' && (fn as Function).name?.startsWith('register'),
			) as (registry: OpenAPIRegistry) => void;
			if (registerFn) {
				registerFn(registry);
				console.log(`✓ Registered paths for domain: ${domain}`);
			}
		} catch (error) {
			// Ignore domains without paths.ts
		}
	}
}

async function generate() {
	await registerAllPaths();

	// ---------------------------------------------------------------------------
	// Generate spec
	// ---------------------------------------------------------------------------
	const generator = new OpenApiGeneratorV3(registry.definitions);
	const spec = generator.generateDocument({
		openapi: '3.0.3',
		info: {
			title: 'BEKIND API',
			version: '1.0.0',
			description: 'BEKIND backend REST API. Spec is generated from Zod contracts — do not edit openapi.json manually.',
		},
		servers: [
			{ url: '/', description: 'Current host' },
			{ url: '/bekind', description: 'BEKIND API' },
		],
	});

	mkdirSync(OUTPUT_DIR, { recursive: true });
	writeFileSync(OUTPUT_FILE, JSON.stringify(spec, null, 2));
	console.log(`✅  OpenAPI spec written to ${OUTPUT_FILE}`);
}

generate();
