#!/usr/bin/env node
//
// audit-dev-wire / index.ts — Entry point.
//
// Static parity check between the generated frontend service URLs and the
// generated backend controller routes. Phase 3e gate of /ba-develop.
//
// Usage:
//
//   npx --prefer-offline tsx skills/development/audit-dev-wire/cli/audit-dev-wire/index.ts \
//     --project-path  "<backend-root>" \
//     --web-path      "<web-root>"     \
//     --module-code   "<MODULE>" \
//     --app-code      "<APP>" \
//     --mode audit
//
// Exit code: 0 when no `err` findings, 1 otherwise.
import { Command } from 'commander'
import path from 'node:path'
import { mkdir, writeFile } from 'node:fs/promises'
import { validateArgs } from './validate.js'
import { audit, reportPath } from './audit.js'
import type { AuditDevWireOutput, Finding } from './types.js'

const program = new Command()

program
  .name('audit-dev-wire')
  .description('Static parity check between generated frontend URLs and backend routes (DEV-WIRE-001). Phase 3e gate of /ba-develop.')
  .requiredOption('--project-path <path>', 'Absolute path to the .NET backend root (src/<Ns>.Api/Controllers/**)')
  .option('--web-path <path>', 'Absolute path to the web project root (src/features/**). Defaults to <project-path>/web/<appCode>-web.')
  .requiredOption('--module-code <code>', 'Active module code (PRD scope)')
  .requiredOption('--app-code <code>', 'Active application code (PRD scope)')
  .option('--mode <mode>', 'audit | apply (apply is a stub in MVP)', 'audit')
  .option('--rules <list>', 'Comma-separated rule codes (e.g. DEV-WIRE-001). Default = all implemented rules')
  .option('--no-write-report', 'Skip writing _audit/dev-wire-<module>.md (stdout only)')
  .parse(process.argv)

const opts = program.opts()

const webPathDefault = path.join(opts.projectPath as string, 'web', `${(opts.appCode as string).toLowerCase()}-web`)
const raw = {
  backendPath: opts.projectPath as string,
  webPath: (opts.webPath as string | undefined) ?? webPathDefault,
  moduleCode: opts.moduleCode as string,
  appCode: opts.appCode as string,
  mode: opts.mode as string,
  rules: typeof opts.rules === 'string'
    ? (opts.rules as string).split(',').map((s) => s.trim()).filter(Boolean)
    : [],
}
const writeReport = opts.writeReport !== false

const validation = validateArgs(raw)
if (!validation.valid || !validation.args) {
  const output: AuditDevWireOutput = {
    success: false,
    command: 'audit-dev-wire',
    data: { mode: (raw.mode as 'audit' | 'apply') ?? 'audit', rulesRun: [], valid: false },
    report: null,
    auditReport: null,
    filesModified: [],
    errors: validation.errors,
    warnings: [],
    nextSteps: ['Fix the CLI arguments and retry.'],
  }
  console.log(JSON.stringify(output, null, 2))
  process.exit(1)
}

const args = validation.args

async function main(): Promise<void> {
  try {
    const report = await audit(args)

    if (writeReport) {
      const dest = reportPath(args.backendPath, args.moduleCode)
      await mkdir(path.dirname(dest), { recursive: true })
      await writeFile(dest, report.markdown, 'utf8')
    }

    const valid = report.counts.errors === 0
    const rulesRun = args.rules.length > 0 ? args.rules : Object.keys(report.byRule)

    const stripped = report.findings.map((f: Finding) => ({
      dimension: f.dimension,
      code: f.code,
      severity: f.severity,
      label: f.label,
      params: f.params,
      solution: f.solution,
      fixSkill: f.fixSkill,
      fixPhaseKey: f.fixPhaseKey,
    }))

    const nextSteps: string[] = []
    if (report.counts.errors > 0) {
      nextSteps.push(`${report.counts.errors} ERROR finding(s) — blocking Phase 3e gate of /ba-develop.`)
      nextSteps.push('Re-run /ba-develop after re-invoking the missing backend scaffolder.')
    }

    const output: AuditDevWireOutput = {
      success: true,
      command: 'audit-dev-wire',
      data: { mode: args.mode, rulesRun, valid },
      report,
      auditReport: {
        scope: 'devWire',
        applicationCode: args.appCode,
        moduleCode: args.moduleCode,
        findings: stripped,
      },
      filesModified: [],
      errors: [],
      warnings: [],
      nextSteps,
    }
    console.log(JSON.stringify(output, null, 2))
    process.exit(valid ? 0 : 1)
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err)
    const output: AuditDevWireOutput = {
      success: false,
      command: 'audit-dev-wire',
      data: { mode: args.mode, rulesRun: [], valid: false },
      report: null,
      auditReport: null,
      filesModified: [],
      errors: [`Unexpected error: ${message}`],
      warnings: [],
      nextSteps: ['Review the error and retry.'],
    }
    console.log(JSON.stringify(output, null, 2))
    process.exit(1)
  }
}

void main()
