#!/usr/bin/env node

/**
 * Static Route Generation Script
 * Scans controller files and generates a static route manifest
 * This replaces the dynamic file system scanning at runtime
 */

const fs = require('fs');
const path = require('path');
const Mustache = require('mustache');

/**
 * Static Route Generator Class
 *
 * Provides functionality for scanning controller directories and generating
 * static route manifests for Express.js applications. This replaces dynamic
 * file system scanning at runtime with a pre-generated manifest.
 */
class StaticRouteGenerator {
	/**
	 * Initializes and runs the complete route generation process
	 */
	static init(options = {}) {
		const {
			log = true,
			controllersDir = path.resolve(process.cwd(), 'src/controllers'),
			outputPath = path.resolve(process.cwd(), 'src/routes.ts'),
		} = options;

		if (log) console.log('🔍 Scanning controllers...');

		const routes = this.scanControllers(controllersDir);

		if (log) console.log(`📝 Generating route manifest with ${routes.length} routes...`);

		this.generateManifest(routes, outputPath);

		if (log) console.log(`✅ Route manifest generated at: ${outputPath}`);
	}

	/**
	 * Scans controller directories and builds route configuration
	 */
	static scanControllers(controllersDir) {
		const routes = [];

		if (!fs.existsSync(controllersDir)) {
			console.warn(`⚠️  Controllers directory not found: ${controllersDir}`);
			return routes;
		}

		const scanDir = (dir, prefix = '') => {
			const items = fs.readdirSync(dir);

			for (const item of items) {
				const fullPath = path.join(dir, item);
				const stat = fs.statSync(fullPath);

				if (stat.isDirectory()) {
					// Recursively scan subdirectories
					scanDir(fullPath, prefix + item + '/');
				} else if (item === 'index.ts' || item === 'index.js') {
					// Found a controller index file
					const routePath = prefix.slice(0, -1); // Remove trailing slash
					const controllerPath = path
						.relative(path.resolve(process.cwd(), 'src'), fullPath)
						.replace(/\\/g, '/')
						.replace('.ts', '')
						.replace('.js', '');

					routes.push({
						path: routePath,
						controller: controllerPath,
						methods: this.extractMethods(fullPath),
					});
				}
			}
		};

		scanDir(controllersDir);
		return routes;
	}

	/**
	 * Extracts HTTP methods from controller file
	 */
	static extractMethods(controllerFile) {
		try {
			const content = fs.readFileSync(controllerFile, 'utf8');

			// Check if this is a bulk or CRUD controller by checking for {id}.ts file
			const dir = path.dirname(controllerFile);
			const hasIdFile = fs.existsSync(path.join(dir, '{id}.ts'));
			const isBulkController = !hasIdFile;

			const methods = [];

			// Always present methods
			if (content.includes('post:')) methods.push('POST');
			if (content.includes('put:')) methods.push('PUT');
			if (content.includes('delete:')) methods.push('DELETE');

			// GET is only present in non-bulk controllers
			if (!isBulkController && content.includes('get:')) methods.push('GET');

			return methods;
		} catch (error) {
			console.warn(`⚠️  Could not extract methods from ${controllerFile}:`, error.message);
			return [];
		}
	} /**
	 * Generates the route manifest file
	 */
	static generateManifest(routes, outputPath) {
		const template = `/**
 * Auto-generated route manifest
 * Generated on: {{timestamp}}
 * Do not edit manually - use 'pnpm gen-routes' to regenerate
 */

export interface RouteConfig {
	path: string;
	controller: string;
	methods: string[];
}

export const routes: RouteConfig[] = [
{{#routes}}	{
		path: "{{{path}}}",
		controller: "{{{controller}}}",
		methods: [{{#methods}}"{{.}}",{{/methods}}]
	},
{{/routes}}];

export default routes;
`;

		const data = {
			routes,
			timestamp: new Date().toISOString(),
		};

		const output = Mustache.render(template, data);

		// Ensure output directory exists
		const outputDir = path.dirname(outputPath);
		if (!fs.existsSync(outputDir)) {
			fs.mkdirSync(outputDir, { recursive: true });
		}

		fs.writeFileSync(outputPath, output, 'utf8');
	}
}

// CLI interface
if (require.main === module) {
	const args = process.argv.slice(2);
	const options = {};

	// Parse command line arguments
	for (let i = 0; i < args.length; i++) {
		const arg = args[i];
		if (arg === '--controllers' && args[i + 1]) {
			options.controllersDir = args[i + 1];
			i++;
		} else if (arg === '--output' && args[i + 1]) {
			options.outputPath = args[i + 1];
			i++;
		} else if (arg === '--quiet') {
			options.log = false;
		}
	}

	StaticRouteGenerator.init(options);
}

module.exports = StaticRouteGenerator;
