/**
 * Pattern Detector — analyzes project files to detect coding patterns.
 * Uses direct file analysis rather than a forked subagent for speed.
 */

import { readFile } from 'fs/promises'
import { join } from 'path'
import { getCwd } from '../../utils/cwd.js'
import { logForDebugging } from '../../utils/debug.js'
import type { PatternProfile } from './types.js'

interface PackageJson {
  dependencies?: Record<string, string>
  devDependencies?: Record<string, string>
  scripts?: Record<string, string>
}

/**
 * Detect patterns by analyzing package.json and project structure.
 */
export async function detectPatterns(): Promise<PatternProfile> {
  const cwd = getCwd()
  let pkg: PackageJson = {}

  try {
    const content = await readFile(join(cwd, 'package.json'), 'utf-8')
    pkg = JSON.parse(content) as PackageJson
  } catch {
    // No package.json — continue with defaults
  }

  const allDeps = {
    ...pkg.dependencies,
    ...pkg.devDependencies,
  }
  const scripts = pkg.scripts ?? {}

  const profile: PatternProfile = {
    version: 1,
    testFramework: detectTestFramework(allDeps, scripts),
    stateManagement: detectStateManagement(allDeps),
    namingConvention: 'camelCase', // default for JS/TS
    errorHandlingStyle: 'try-catch',
    fileOrganization: 'by-feature',
    packageManager: await detectPackageManager(cwd),
    primaryLanguage: detectLanguage(allDeps, cwd),
    framework: detectFramework(allDeps),
    analyzedAt: Date.now(),
  }

  logForDebugging(
    `Patterns detected: ${profile.primaryLanguage}, ` +
      `framework=${profile.framework}, ` +
      `tests=${profile.testFramework}`,
  )

  return profile
}

function detectTestFramework(
  deps: Record<string, string>,
  scripts: Record<string, string>,
): string | null {
  const scriptValues = Object.values(scripts).join(' ')

  if (deps.vitest || scriptValues.includes('vitest')) return 'vitest'
  if (deps.jest || deps['@jest/core'] || scriptValues.includes('jest'))
    return 'jest'
  if (deps.mocha || scriptValues.includes('mocha')) return 'mocha'
  if (deps['@playwright/test']) return 'playwright'
  if (deps.cypress) return 'cypress'
  if (deps.ava) return 'ava'
  return null
}

function detectStateManagement(
  deps: Record<string, string>,
): string | null {
  if (deps.zustand) return 'zustand'
  if (deps['@reduxjs/toolkit'] || deps.redux) return 'redux'
  if (deps.jotai) return 'jotai'
  if (deps.recoil) return 'recoil'
  if (deps.mobx) return 'mobx'
  if (deps.valtio) return 'valtio'
  if (deps.pinia) return 'pinia'
  if (deps.vuex) return 'vuex'
  return null
}

function detectFramework(deps: Record<string, string>): string | null {
  if (deps.next) return 'next'
  if (deps.nuxt) return 'nuxt'
  if (deps.react) return 'react'
  if (deps.vue) return 'vue'
  if (deps.svelte || deps['@sveltejs/kit']) return 'svelte'
  if (deps.angular || deps['@angular/core']) return 'angular'
  if (deps.express) return 'express'
  if (deps.fastify) return 'fastify'
  if (deps.hono) return 'hono'
  if (deps.nestjs || deps['@nestjs/core']) return 'nestjs'
  if (deps.astro) return 'astro'
  if (deps.remix || deps['@remix-run/react']) return 'remix'
  return null
}

function detectLanguage(
  deps: Record<string, string>,
  _cwd: string,
): string {
  if (deps.typescript || deps['@types/node']) return 'typescript'
  return 'javascript'
}

async function detectPackageManager(cwd: string): Promise<string | null> {
  const checks: Array<[string, string]> = [
    ['bun.lockb', 'bun'],
    ['bun.lock', 'bun'],
    ['pnpm-lock.yaml', 'pnpm'],
    ['yarn.lock', 'yarn'],
    ['package-lock.json', 'npm'],
  ]

  for (const [file, manager] of checks) {
    try {
      await readFile(join(cwd, file))
      return manager
    } catch {
      // File doesn't exist
    }
  }

  return null
}
