/**
 * commands/detect-project.mjs — detect-project command (C29).
 */

import { execSync } from 'node:child_process'
import { existsSync, readdirSync, readFileSync } from 'node:fs'
import { extname, join, resolve } from 'node:path'
import { detectWorktree } from '../git/worktree-detect.mjs'
import { err, ok } from '../util/result.mjs'

export function cmdDetectProject(projectDir) {
	if (!projectDir) return err('Usage: apt-tools detect-project <project-dir>')
	const targetDir = resolve(projectDir)

	// Check if already initialized
	const configPath = join(targetDir, '.aperant', 'config.json')
	if (existsSync(configPath)) {
		let existingConfig = null
		try {
			existingConfig = JSON.parse(readFileSync(configPath, 'utf-8'))
		} catch {
			/* malformed */
		}
		return ok({
			status: 'already-initialized',
			command: 'detect-project',
			projectDir: targetDir,
			project_type: existingConfig?.project_type ?? 'unknown',
		})
	}

	// Count source files (common languages — NOT in node_modules, .git, dist, build)
	const sourceExts = new Set([
		'.js',
		'.ts',
		'.jsx',
		'.tsx',
		'.py',
		'.rs',
		'.go',
		'.java',
		'.rb',
		'.vue',
		'.svelte',
	])
	const ignoreDirs = new Set([
		'node_modules',
		'.git',
		'dist',
		'build',
		'.next',
		'__pycache__',
		'target',
		'vendor',
	])
	let sourceFileCount = 0
	const MAX_SCAN = 500

	function countSources(dir, depth) {
		if (depth > 5 || sourceFileCount > MAX_SCAN) return
		try {
			for (const entry of readdirSync(dir, { withFileTypes: true })) {
				if (entry.isDirectory() && !ignoreDirs.has(entry.name) && !entry.name.startsWith('.')) {
					countSources(join(dir, entry.name), depth + 1)
				} else if (entry.isFile()) {
					const ext = extname(entry.name)
					if (sourceExts.has(ext)) sourceFileCount++
				}
				if (sourceFileCount > MAX_SCAN) return
			}
		} catch {
			/* permission errors, etc */
		}
	}
	countSources(targetDir, 0)

	// Detect project signals
	const hasSrcDir = existsSync(join(targetDir, 'src'))
	const hasPackageJson = existsSync(join(targetDir, 'package.json'))
	const hasCargoToml = existsSync(join(targetDir, 'Cargo.toml'))
	const hasPyproject = existsSync(join(targetDir, 'pyproject.toml'))
	const hasGoMod = existsSync(join(targetDir, 'go.mod'))
	const hasTsconfig = existsSync(join(targetDir, 'tsconfig.json'))
	const hasGit = existsSync(join(targetDir, '.git'))

	// Detect existing framework
	const hasClaudeMd = existsSync(join(targetDir, 'CLAUDE.md'))
	const hasAgentsMd = existsSync(join(targetDir, 'AGENTS.md'))
	const hasBmad = existsSync(join(targetDir, '_bmad-output'))
	const hasPlanning = existsSync(join(targetDir, '.planning'))

	// Read package.json for stack detection
	let packageJson = null
	if (hasPackageJson) {
		try {
			packageJson = JSON.parse(readFileSync(join(targetDir, 'package.json'), 'utf-8'))
		} catch {
			/* malformed */
		}
	}

	const deps = { ...packageJson?.dependencies, ...packageJson?.devDependencies }
	const detectedStack = []
	if (deps) {
		if (deps['react']) detectedStack.push('React ' + (deps['react'].replace(/[\^~]/, '') || ''))
		if (deps['next']) detectedStack.push('Next.js')
		if (deps['vue']) detectedStack.push('Vue')
		if (deps['svelte'] || deps['@sveltejs/kit']) detectedStack.push('Svelte')
		if (deps['express']) detectedStack.push('Express')
		if (deps['fastify']) detectedStack.push('Fastify')
		if (deps['convex']) detectedStack.push('Convex')
		if (deps['prisma'] || deps['@prisma/client']) detectedStack.push('Prisma')
		if (deps['drizzle-orm']) detectedStack.push('Drizzle')
		if (deps['tailwindcss']) detectedStack.push('Tailwind CSS')
		if (deps['typescript']) detectedStack.push('TypeScript')
		if (deps['vitest']) detectedStack.push('Vitest')
		if (deps['jest']) detectedStack.push('Jest')
		if (deps['electron']) detectedStack.push('Electron')
	}

	// Git commit count (cheap heuristic for fresh init)
	let commitCount = 0
	if (hasGit) {
		try {
			const count = execSync('git rev-list --count HEAD 2>/dev/null', {
				cwd: targetDir,
				encoding: 'utf-8',
			}).trim()
			commitCount = parseInt(count, 10) || 0
		} catch {
			commitCount = 0
		}
	}

	// Greenfield vs brownfield (per spec 4.2, addressing G10: scaffold-aware)
	const isScaffolded = hasPackageJson && sourceFileCount > 15 && commitCount <= 3
	const isGreenfield =
		!isScaffolded && (!hasSrcDir || sourceFileCount < 5 || (hasGit && commitCount <= 1))

	// Detect project type (addressing G2)
	let projectType = 'unknown'
	if (hasPackageJson) {
		const pkg = packageJson
		if (pkg?.workspaces || existsSync(join(targetDir, 'pnpm-workspace.yaml'))) {
			projectType = 'monorepo'
		} else if (pkg?.bin) {
			projectType = 'cli-tool'
		} else if (
			deps?.['next'] ||
			deps?.['react'] ||
			deps?.['vue'] ||
			deps?.['svelte'] ||
			deps?.['@sveltejs/kit']
		) {
			projectType = 'web-app'
		} else if (deps?.['express'] || deps?.['fastify'] || deps?.['hono'] || deps?.['koa']) {
			projectType = 'api-service'
		} else if (pkg?.main || pkg?.module || pkg?.exports) {
			projectType = 'library'
		}
	} else if (hasCargoToml || hasGoMod || hasPyproject) {
		projectType = 'cli-tool'
	}

	// Framework-aware risk map defaults (addressing G11)
	const riskMapDefaults = {
		critical_paths: [
			'**/auth/**',
			'**/middleware/auth*',
			'**/*.env*',
			'**/migration*/**',
			'**/schema*',
		],
		elevated_paths: ['**/api/**', '**/routes/**', '**/store/**', '**/hooks/use*'],
		safe_paths: ['**/*.css', '**/*.md', '**/*.test.*', '**/*.spec.*'],
	}
	if (deps?.['next']) {
		riskMapDefaults.critical_paths.push('**/middleware.ts', '**/middleware.js')
		riskMapDefaults.elevated_paths.push('**/app/api/**', '**/pages/api/**')
	}
	if (deps?.['convex']) {
		riskMapDefaults.critical_paths.push('**/convex/schema.*', '**/convex/auth.*')
		riskMapDefaults.elevated_paths.push('**/convex/**')
	}
	if (deps?.['prisma'] || deps?.['@prisma/client']) {
		riskMapDefaults.critical_paths.push('**/prisma/schema.prisma', '**/prisma/migrations/**')
	}
	if (deps?.['drizzle-orm']) {
		riskMapDefaults.critical_paths.push('**/drizzle/**', '**/db/schema.*')
	}

	// Check for test infrastructure
	const hasTests =
		existsSync(join(targetDir, '__tests__')) ||
		existsSync(join(targetDir, 'tests')) ||
		existsSync(join(targetDir, 'test')) ||
		(deps && (deps['vitest'] || deps['jest'] || deps['mocha']))

	return ok({
		status: 'ok',
		command: 'detect-project',
		projectDir: targetDir,
		classification: isGreenfield ? 'greenfield' : 'brownfield',
		is_scaffolded: isScaffolded,
		project_type: projectType,
		source_file_count: Math.min(sourceFileCount, MAX_SCAN),
		has_src_dir: hasSrcDir,
		has_git: hasGit,
		commit_count: commitCount,
		has_tests: hasTests,
		detected_stack: detectedStack,
		risk_map_defaults: riskMapDefaults,
		existing_framework: {
			claude_md: hasClaudeMd,
			agents_md: hasAgentsMd,
			bmad: hasBmad,
			planning: hasPlanning,
		},
		package_name: packageJson?.name ?? null,
		package_description: packageJson?.description ?? null,
		worktree: detectWorktree(targetDir),
	})
}
