import fs from 'node:fs'

import { join } from 'node:path'
import { cwd as _cwd, env, argv } from 'node:process'
import { ESLint } from 'eslint'
import * as prettier from 'prettier'
import { loadEnv } from 'vite'

const cwd = _cwd()

export async function formatAndWriteCode(outPath: string, code: string) {
	const prettyCode = await prettier.format(code, { parser: 'typescript' })
	fs.writeFileSync(outPath, prettyCode)
}

export async function runEsLintOnDir(dir: string) {
	// ! only run if eslint.config.js exists
	if (!fs.existsSync(join(cwd, 'eslint.config.js'))) {
		console.log('no eslint.config.js found, skipping eslint')
		return
	}

	const eslint = new ESLint({ fix: true, overrideConfigFile: join(cwd, 'eslint.config.js'), cwd })
	const results = await eslint.lintFiles(`${dir}/**/*.ts`)

	await ESLint.outputFixes(results)
}

// =============================================================================
// TYPES
// =============================================================================

interface ParsedConfig {
	readonly baseUrl: string
	readonly openApiUrl: string
	readonly schemaId?: string
	readonly outputFile?: string
	readonly useUtilityFunctions?: boolean
	readonly useTableSchema?: boolean
	readonly verbose?: boolean
	readonly cwd: string
	env: Partial<Record<string, string>>
}

interface ConfigOptions {
	readonly schemaId: string | undefined
	readonly defaultOutputFile?: string
	readonly allowedFlags?: readonly string[]
}

// =============================================================================
// ARGUMENT PARSING UTILITIES
// =============================================================================

/**
 * Parse command line flags (arguments starting with --)
 */
function parseFlags(args: string[]): Set<string> {
	return new Set(
		args
			.filter(arg => arg.startsWith('--'))
			.map(arg => arg.slice(2)) // Remove '--' prefix
	)
}

/**
 * Parse command line arguments that are key-value pairs (--key=value)
 */
function parseKeyValueArgs(args: string[]): Record<string, string> {
	const keyValuePairs: Record<string, string> = {}

	args
		.filter(arg => arg.startsWith('--') && arg.includes('='))
		.forEach((arg) => {
			const [key, ...valueParts] = arg.slice(2).split('=')
			if (key && valueParts.length > 0) {
				keyValuePairs[key] = valueParts.join('=')
			}
		})

	return keyValuePairs
}

// /**
//  * Parse positional arguments (non-flag arguments)
//  */
// function parsePositionalArgs(args: string[]): string[] {
// 	return args.filter(arg => !arg.startsWith('--'))
// }

// =============================================================================
// MAIN PARSING FUNCTION
// =============================================================================

/**
 * Parse command line arguments and environment variables into a structured configuration
 *
 * @example
 * ```bash
 * # Basic usage
 * node script.js
 *
 * # With directory
 * node script.js
 *
 * # With flags
 * node script.js --verbose
 *
 * # With key-value pairs
 * node script.js --schema-id=UserResponse --output=src/forms/user.ts
 *
 * # Combined
 * node script.js --schema-id=UserResponse --output=src/forms/user.ts
 * ```
 */
export function parseConfig(options: ConfigOptions): ParsedConfig {
	const {
		schemaId,
		defaultOutputFile,
		allowedFlags = [
			'verbose',
			'utility-functions',
			'table-schema'
		]
	} = options

	// Load environment variables
	const currentCwd = cwd
	const environment = loadEnv('', currentCwd)

	// Parse command line arguments
	const args = argv.slice(2) // Remove 'node' and script path
	const flags = parseFlags(args)
	const keyValueArgs = parseKeyValueArgs(args)
	// const positionalArgs = parsePositionalArgs(args)

	// Validate flags
	const invalidFlags = Array.from(flags).filter(flag => !allowedFlags.includes(flag) && !flag.includes('=')
	)

	if (invalidFlags.length > 0) {
		console.warn(`Warning: Unknown flags detected: ${invalidFlags.join(', ')}`)
		console.warn(`Allowed flags: ${allowedFlags.join(', ')}`)
	}

	// Build configuration
	const baseUrl = keyValueArgs.baseurl || keyValueArgs['base-url'] || 'http://localhost:8000'

	const config: ParsedConfig = {
		// URLs and paths
		baseUrl,
		openApiUrl: `${baseUrl}/openapi.json`,

		// Flags
		useUtilityFunctions: flags.has('utility-functions'),
		useTableSchema: flags.has('table-schema'),
		verbose: flags.has('verbose'),

		// Key-value arguments with fallbacks
		schemaId: keyValueArgs['schema-id'] || keyValueArgs.schemaId || keyValueArgs.schema || schemaId,
		outputFile: keyValueArgs.output || keyValueArgs.out || defaultOutputFile,

		// System info
		cwd: currentCwd,
		env: { ...environment, ...env } // Merge loaded env with process.env
	} as const

	// Log configuration if verbose
	if (config.verbose) {
		console.log('Parsed configuration:', {
			...config,
			env: '[hidden]' // Don't log environment variables
		})
	}

	return config
}

// =============================================================================
// UTILITY HELPERS
// =============================================================================

/**
 * Print help message for command line usage
 */
export function printHelp(scriptName: string = 'script'): void {
	console.log(`
Usage: ${scriptName} [directory] [options]

Arguments:
  directory                Target directory (default: .bagelink)

Options:
  --verbose                Enable verbose logging
  --utility-functions      Use utility functions in generated code
  --table-schema           Generate table schema instead of form schema
  --baseurl=<url>          Specify base URL (default: http://localhost:8000)
  --schema-id=<id>         Specify schema ID to process
  --output=<path>          Specify output file path

Examples:
  ${scriptName}                            # Use defaults
  ${scriptName}                            # Custom directory
  ${scriptName} --verbose                  # With flags
  ${scriptName} --baseurl=https://api.example.com  # Custom base URL
  ${scriptName} --schema-id=UserResponse   # With schema ID
  ${scriptName} --output=forms.ts          # Combined usage
`)
}

/**
 * Validate required configuration values
 */
export function validateConfig(config: ParsedConfig, required: (keyof ParsedConfig)[] = []): void {
	const missing = required.filter((key) => {
		const value = config[key]
		return value === undefined || value === null || value === ''
	})

	if (missing.length > 0) {
		throw new Error(`Missing required configuration: ${missing.join(', ')}`)
	}
}
