import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { ApiError, ERROR_CODES } from '@/lib/api/errors'
import { batteryDispatchSchema, type BatteryDispatchInput } from '@/lib/api/schemas'
import { demoBaseTimestamp } from '@/lib/demo/config'
import { listBatteries, simulateBatteryDispatch } from '@/lib/services/bess-service'

export const dynamic = 'force-dynamic'

/** The storage units available to plan against. */
export const GET = apiRoute({ permission: 'twin.read', limit: 60 }, async ({ searchParams }) => ({
  batteries: await listBatteries({
    twinCode: searchParams.get('twin') ?? undefined,
    ts: searchParams.get('clock') === 'demo' ? demoBaseTimestamp() : undefined,
  }),
}))

/**
 * Simulate a battery dispatch (§19).
 *
 * A projection, not an instruction. §19 forbids sending a command to a battery, and this
 * route implements no path that could: it reads the unit's state, walks the dispatch
 * forward and returns the curve. The permission is `twin.simulate` for the same reason the
 * prevention route takes it — there is no control here to permit.
 */
export const POST = apiRoute<Record<string, string>, BatteryDispatchInput>(
  { permission: 'twin.simulate', bodySchema: batteryDispatchSchema, limit: 40 },
  async ({ body, user, request }) => {
    const result = await simulateBatteryDispatch({
      twinCode: body.twinCode,
      assetCode: body.assetCode,
      requestMw: body.requestMw,
      durationMin: body.durationMin,
      ts: body.demoClock ? demoBaseTimestamp() : undefined,
    })
    if (!result) throw new ApiError(ERROR_CODES.notFound)

    await writeAudit({
      action: AUDIT_ACTIONS.batteryDispatchSimulated,
      entity: 'asset',
      entityId: result.batteryCode,
      user,
      request,
      detail: `${body.requestMw} MW for ${body.durationMin} min: held ${result.sustainedMin} min, SOC ${result.socStartPct} → ${result.socEndPct} % (simulated, no command sent)`,
    })

    return result
  },
)
