import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { ApiError, ERROR_CODES } from '@/lib/api/errors'
import { toPerturbation } from '@/lib/api/overlay'
import { liveGridSimulateSchema, type LiveGridSimulateInput } from '@/lib/api/schemas'
import { demoBaseTimestamp } from '@/lib/demo/config'
import { simulatePrevention } from '@/lib/services/live-grid-service'

export const dynamic = 'force-dynamic'

/**
 * Visualise the fix (§46–§48).
 *
 * Runs the recommended strategy inside the sandbox and returns the scene before and after,
 * with the flow re-solved on both sides so redistribution is visible rather than asserted.
 *
 * It writes nothing to live state. The isolation test enforces that; this comment only
 * records why the route takes `twin.simulate` rather than a control permission — there is
 * no control here to permit.
 */
export const POST = apiRoute<Record<string, string>, LiveGridSimulateInput>(
  { permission: 'twin.simulate', bodySchema: liveGridSimulateSchema, limit: 30 },
  async ({ body, user, request }) => {
    const result = await simulatePrevention({
      ts: body.demoClock ? demoBaseTimestamp() : undefined,
      twinCode: body.twinCode,
      scenario: body.scenario ?? null,
      overlay: toPerturbation(body.overlay),
      assetCode: body.preventForAsset ?? null,
      offsetMin: body.offsetMin ?? 0,
    })
    if (!result) throw new ApiError(ERROR_CODES.notFound)

    await writeAudit({
      action: AUDIT_ACTIONS.liveGridSimulated,
      entity: 'live_grid',
      entityId: result.assetCode ?? result.twinCode,
      user,
      request,
      detail: `${result.strategy.label}: regional risk ${result.before.peakRisk} → ${result.after.peakRisk} (simulated)`,
    })

    return result
  },
)
