import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { resilienceTestSchema, type ResilienceTestInput } from '@/lib/api/schemas'
import {
  getResilience,
  listResilienceTests,
  persistResilienceTest,
  runResilienceTest,
} from '@/lib/services/resilience-service'

export const dynamic = 'force-dynamic'

/** The national resilience score, its factors, and the tests already run. */
export const GET = apiRoute({ permission: 'grid.read', limit: 30 }, async ({ searchParams }) => {
  const includeEnvelope = searchParams.get('envelope') !== 'false'
  const [resilience, tests] = await Promise.all([
    getResilience({ includeEnvelope }),
    listResilienceTests(10),
  ])

  return {
    ...resilience,
    tests: tests.map((test) => ({
      code: test.code,
      disturbance: test.disturbance,
      magnitude: test.magnitude,
      scoreBefore: test.scoreBefore,
      scoreDuring: test.scoreDuring,
      scoreAfter: test.scoreAfter,
      recoveryMin: test.recoveryMin,
      verdict: test.verdict,
      verdictAr: test.verdictAr,
      createdAt: test.createdAt.getTime(),
    })),
  }
})

/**
 * The Resilience Lab (§40).
 *
 * Applies a disturbance to the twin and measures before, during and after. Expensive —
 * each phase rebuilds the national model and walks a cascade per load-serving asset — so
 * the rate limit here is deliberately low.
 */
export const POST = apiRoute<Record<string, string>, ResilienceTestInput>(
  { permission: 'resilience.run', bodySchema: resilienceTestSchema, limit: 8 },
  async ({ body, user, request }) => {
    const result = await runResilienceTest(body.disturbance, {
      magnitude: body.magnitude,
      durationMin: body.durationMin,
    })

    if (body.persist) await persistResilienceTest(result, { userId: user.id })

    await writeAudit({
      action: AUDIT_ACTIONS.resilienceTested,
      entity: 'grid',
      entityId: body.disturbance,
      user,
      request,
      detail: `${result.before.score} → ${result.during.score} → ${result.after.score}, recovery ${result.recoveryMin} min`,
    })

    return { ...result, source: 'simulated' }
  },
)
