/**
 * Environment Types Generator
 *
 * Generates src/generated/env.d.ts by analyzing local .env files
 */

import { join } from 'node:path';
import { existsSync, mkdirSync } from 'node:fs';
import { getEnvFilePaths, readEnvFile, isPublicVarKey } from '../../../env-util';
import type { Logger } from '../../../types';

/**
 * Generate TypeScript declarations for environment variables
 */
function generateEnvTypesContent(keys: string[]): string {
	const sortedKeys = [...keys].sort();
	const publicKeys = sortedKeys.filter(isPublicVarKey);

	// Build ProcessEnv interface entries
	const processEnvEntries =
		sortedKeys.length > 0
			? sortedKeys.map((key) => `\t\treadonly ${key}: string;`).join('\n')
			: '\t\t\t// No environment variables found';

	// Build ImportMetaEnv interface entries (only public keys: VITE_*, AGENTUITY_PUBLIC_*, PUBLIC_*)
	const importMetaEnvEntries =
		publicKeys.length > 0
			? publicKeys.map((key) => `\treadonly ${key}: string;`).join('\n')
			: '\t// No VITE_*, AGENTUITY_PUBLIC_*, or PUBLIC_* prefixed variables found';

	return `// @generated
// AUTO-GENERATED from local .env files
// This file is auto-generated by the build tool - do not edit manually

declare global {
	namespace NodeJS {
		interface ProcessEnv {
${processEnvEntries}
		}
	}
}

// Vite-compatible environment types
// Only includes variables with VITE_, AGENTUITY_PUBLIC_, or PUBLIC_ prefix
interface ImportMetaEnv {
${importMetaEnvEntries}
}

interface ImportMeta {
	readonly env: ImportMetaEnv;
}

export {};

// FOUND AN ERROR IN THIS FILE?
// Please file an issue at https://github.com/agentuity/sdk/issues
// or if you know the fix please submit a PR!
`;
}

export interface GenerateEnvTypesOptions {
	/** Root directory of the project */
	rootDir: string;
	/** Source directory (typically rootDir/src) */
	srcDir: string;
	/** Logger instance */
	logger: Logger;
	/** Whether building for production (affects .env file precedence) */
	isProduction: boolean;
	/** Optional config profile name (e.g., 'staging', 'test') for .env.{profile} files */
	profile?: string;
}

/**
 * Generate environment type definitions from local .env files
 *
 * @param options - Generation options
 * @returns true if types were generated, false if no env files found
 */
export async function generateEnvTypes(options: GenerateEnvTypesOptions): Promise<boolean> {
	const { rootDir, srcDir, logger, isProduction, profile } = options;

	logger.debug('[env-types] Starting env types generation...');
	logger.debug(`[env-types] rootDir: ${rootDir}`);
	logger.debug(`[env-types] srcDir: ${srcDir}`);
	logger.debug(`[env-types] isProduction: ${isProduction}`);
	logger.debug(`[env-types] profile: ${profile ?? '(none)'}`);

	// Get env file paths based on build mode and profile
	// Dev: ['.env.{profile}', '.env.development', '.env'] - later files override earlier
	// Prod: ['.env.{profile}', '.env', '.env.production'] - later files override earlier
	const envFilePaths = getEnvFilePaths(rootDir, { isProduction, configName: profile });
	logger.debug(`[env-types] Env file paths to check: ${envFilePaths.join(', ')}`);

	// Read and merge env files (later files override earlier)
	const mergedEnv: Record<string, string> = {};
	let foundAnyFile = false;

	for (const filePath of envFilePaths) {
		const envVars = await readEnvFile(filePath);
		const keyCount = Object.keys(envVars).length;

		if (keyCount > 0) {
			foundAnyFile = true;
			logger.debug(`[env-types] Read ${keyCount} vars from ${filePath}`);

			// Merge - later values override earlier
			for (const [key, value] of Object.entries(envVars)) {
				mergedEnv[key] = value;
			}
		} else {
			logger.debug(`[env-types] No vars found in ${filePath} (file may not exist)`);
		}
	}

	if (!foundAnyFile) {
		logger.debug('[env-types] No .env files found, skipping env types generation');
		return false;
	}

	// Extract just the keys (we don't include values in types)
	const keys = Object.keys(mergedEnv);
	logger.debug(`[env-types] Total unique keys: ${keys.length}`);

	// Determine output path
	const outDir = join(srcDir, 'generated');
	const outputPath = join(outDir, 'env.d.ts');

	// Ensure output directory exists
	if (!existsSync(outDir)) {
		mkdirSync(outDir, { recursive: true });
		logger.debug(`[env-types] Created output directory: ${outDir}`);
	}

	// Generate and write types
	const typesContent = generateEnvTypesContent(keys);
	await Bun.write(outputPath, typesContent);

	const publicKeyCount = keys.filter(isPublicVarKey).length;
	logger.debug(
		`[env-types] Generated env types with ${keys.length} keys (${publicKeyCount} public) at ${outputPath}`
	);

	return true;
}
