/**
 * Project Knowledge Base — orchestrates scanning, persistence, and retrieval.
 *
 * Stores structured project understanding in .sandcode/knowledge/ and
 * provides summaries for system prompt injection.
 */

import { readFile, writeFile, mkdir } from 'fs/promises'
import { join } from 'path'
import { getCwd } from '../../utils/cwd.js'
import { logForDebugging } from '../../utils/debug.js'
import { scanArchitecture, summarizeArchitecture } from './scanner.js'
import type {
  ArchitectureGraph,
  HotspotMap,
  PatternProfile,
  ProjectKnowledge,
} from './types.js'

const KB_DIR = '.sandcode/knowledge'

function getKBPath(filename: string): string {
  return join(getCwd(), KB_DIR, filename)
}

async function ensureKBDir(): Promise<void> {
  await mkdir(join(getCwd(), KB_DIR), { recursive: true })
}

/**
 * Load a JSON knowledge file, returning null if missing or invalid.
 */
async function loadKBFile<T>(filename: string): Promise<T | null> {
  try {
    const content = await readFile(getKBPath(filename), 'utf-8')
    return JSON.parse(content) as T
  } catch {
    return null
  }
}

/**
 * Save a knowledge file.
 */
async function saveKBFile<T>(filename: string, data: T): Promise<void> {
  await ensureKBDir()
  await writeFile(getKBPath(filename), JSON.stringify(data, null, 2), 'utf-8')
}

/**
 * Load the full project knowledge base.
 */
export async function loadProjectKnowledge(): Promise<ProjectKnowledge> {
  const [architecture, patterns, hotspots] = await Promise.all([
    loadKBFile<ArchitectureGraph>('architecture.json'),
    loadKBFile<PatternProfile>('patterns.json'),
    loadKBFile<HotspotMap>('hotspots.json'),
  ])
  return { architecture, patterns, hotspots }
}

/**
 * Build or refresh the architecture graph.
 */
export async function buildArchitecture(): Promise<ArchitectureGraph> {
  const rootDir = getCwd()
  logForDebugging('Building architecture graph...')
  const graph = await scanArchitecture(rootDir)
  await saveKBFile('architecture.json', graph)
  logForDebugging(
    `Architecture graph built: ${Object.keys(graph.dependencies).length} files, ` +
      `${graph.entryPoints.length} entry points`,
  )
  return graph
}

/**
 * Save a pattern profile (typically generated by a forked subagent).
 */
export async function savePatterns(
  patterns: PatternProfile,
): Promise<void> {
  await saveKBFile('patterns.json', patterns)
}

/**
 * Save a hotspot map.
 */
export async function saveHotspots(hotspots: HotspotMap): Promise<void> {
  await saveKBFile('hotspots.json', hotspots)
}

/**
 * Check if the architecture graph needs rebuilding.
 * Returns true if missing or older than 24 hours.
 */
export async function needsArchitectureRefresh(): Promise<boolean> {
  const arch = await loadKBFile<ArchitectureGraph>('architecture.json')
  if (!arch) return true
  const age = Date.now() - arch.builtAt
  const ONE_DAY = 24 * 60 * 60 * 1000
  return age > ONE_DAY
}

/**
 * Check if patterns need refreshing.
 * Returns true if missing or older than 7 days.
 */
export async function needsPatternsRefresh(): Promise<boolean> {
  const patterns = await loadKBFile<PatternProfile>('patterns.json')
  if (!patterns) return true
  const age = Date.now() - patterns.analyzedAt
  const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000
  return age > SEVEN_DAYS
}

/**
 * Generate a compact project briefing for system prompt injection.
 * Combines architecture summary, patterns, and hotspots into ~500 tokens.
 */
export async function generateProjectBriefing(): Promise<string | null> {
  const kb = await loadProjectKnowledge()

  // Nothing to report if no knowledge exists
  if (!kb.architecture && !kb.patterns) return null

  const sections: string[] = ['<project-knowledge>']

  if (kb.architecture) {
    sections.push('## Architecture')
    sections.push(summarizeArchitecture(kb.architecture))
  }

  if (kb.patterns) {
    sections.push('## Patterns')
    const p = kb.patterns
    const patternLines = [
      p.primaryLanguage && `Language: ${p.primaryLanguage}`,
      p.framework && `Framework: ${p.framework}`,
      p.testFramework && `Tests: ${p.testFramework}`,
      p.stateManagement && `State: ${p.stateManagement}`,
      p.packageManager && `Package manager: ${p.packageManager}`,
      `File organization: ${p.fileOrganization}`,
      `Error handling: ${p.errorHandlingStyle}`,
    ].filter(Boolean)
    sections.push(patternLines.join('\n'))
  }

  if (kb.hotspots && kb.hotspots.byChangeFrequency.length > 0) {
    sections.push('## Hotspots (most-changed files)')
    sections.push(
      kb.hotspots.byChangeFrequency
        .slice(0, 5)
        .map((h) => `  ${h.path} (${h.changes} changes)`)
        .join('\n'),
    )
  }

  sections.push('</project-knowledge>')
  return sections.join('\n')
}
