#!/usr/bin/env node
/**
 * cli:scaffold-tests-from-ac — index.ts
 *
 * Reads `use-case.md` files under a BA module folder, emits one xUnit [Fact]
 * skeleton per Acceptance Criterion (AC). Phase 5 of /ba-develop fills the
 * TODO bodies; DEV-TEST-001 (Wave 3) audits coverage.
 *
 * Invocation:
 *   npx tsx scaffold-tests-from-ac/index.ts \
 *     --spec '{"moduleDir":"…","projectPath":"…","appCode":"crm","module":"pipeline"}' \
 *     [--json]
 */

import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join, relative, resolve } from 'node:path'
import { parseArgs } from 'node:util'
import { findFiles } from '../../../../lib/fs.js'
import { generate } from './generate.js'
import { parseAcFromUseCaseMd } from './parse-ac.js'
import type { ScaffoldTestsFromAcResult, UcWithAc } from './types.js'
import { validate } from './validate.js'

async function main(): Promise<void> {
  const args = parseArgs({
    options: {
      spec: { type: 'string' },
      json: { type: 'boolean', default: false },
    },
    allowPositionals: false,
  })

  if (!args.values.spec) {
    console.error('Error: --spec is required')
    process.exit(2)
  }

  let raw: unknown
  try {
    raw = JSON.parse(args.values.spec)
  } catch {
    console.error('Error: --spec must be valid JSON')
    process.exit(2)
  }

  const validation = validate(raw)
  if (!validation.valid) {
    emit(args.values.json, {
      success: false,
      error: validation.errors.join('; '),
      ucsScanned: 0,
      acsParsed: 0,
      factsEmitted: 0,
      filesCreated: [],
      warnings: validation.warnings,
    })
    process.exit(2)
  }

  const spec = validation.data!
  const moduleDir = resolve(spec.moduleDir)
  const projectPath = resolve(spec.projectPath)

  // Find every use-case.md under <moduleDir>/<section>/...
  // Uses lib/fs.findFiles (minimatch-based) for Node 18+ compat.
  const absoluteMatches = await findFiles('**/use-case.md', { cwd: moduleDir })

  const allUcs: UcWithAc[] = []
  const warnings: string[] = [...validation.warnings]

  for (const absolute of absoluteMatches) {
    const rel = relative(moduleDir, absolute).replace(/\\/g, '/')
    let content: string
    try {
      content = readFileSync(absolute, 'utf8')
    } catch (err) {
      warnings.push(`Cannot read ${rel}: ${(err as Error).message}`)
      continue
    }
    const result = parseAcFromUseCaseMd(content, rel)
    warnings.push(...result.warnings)
    allUcs.push(...result.ucs)
  }

  const { files, ucsScanned, acsParsed, factsEmitted } = generate({ spec, ucs: allUcs })

  const filesCreated: string[] = []
  if (!spec.dryRun) {
    for (const f of files) {
      const absolute = join(projectPath, f.path)
      mkdirSync(dirname(absolute), { recursive: true })
      writeFileSync(absolute, f.content, 'utf8')
      filesCreated.push(relative(projectPath, absolute).replace(/\\/g, '/'))
    }
  } else {
    for (const f of files) filesCreated.push(f.path)
  }

  const result: ScaffoldTestsFromAcResult = {
    success: true,
    ucsScanned,
    acsParsed,
    factsEmitted,
    filesCreated,
    warnings,
  }
  emit(args.values.json, result)
  process.exit(0)
}

function emit(json: boolean | undefined, payload: ScaffoldTestsFromAcResult): void {
  if (json) {
    console.log(JSON.stringify(payload, null, 2))
    return
  }
  if (!payload.success) {
    console.error(`✗ ${payload.error ?? 'failed'}`)
    return
  }
  console.log(`✓ scaffold-tests-from-ac:`)
  console.log(`  UCs scanned   : ${payload.ucsScanned}`)
  console.log(`  ACs parsed    : ${payload.acsParsed}`)
  console.log(`  [Fact]s emitted: ${payload.factsEmitted}`)
  console.log(`  Files created : ${payload.filesCreated.length}`)
  for (const p of payload.filesCreated) console.log(`    + ${p}`)
  if (payload.warnings.length > 0) {
    console.log(`  Warnings:`)
    for (const w of payload.warnings) console.log(`    ! ${w}`)
  }
}

main().catch(err => {
  console.error('Fatal:', (err as Error).message)
  process.exit(2)
})

// Ensure existsSync is used (placeholder for future fs.access)
void existsSync
