import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { ApiError, ERROR_CODES } from '@/lib/api/errors'
import { sensorFaultSchema, type SensorFaultInput } from '@/lib/api/schemas'
import { setSensorFault } from '@/lib/services/sensor-service'

export const dynamic = 'force-dynamic'

/**
 * Break an instrument on purpose, in demonstration or simulation only.
 *
 * The mode check is here, on the server. §7 requires LIVE to reject this, and a check the
 * client performs is a check an attacker skips — so the refusal happens where the request
 * lands, not where the button is.
 *
 * A refusal in LIVE is a 409 rather than a 403: the caller has the right to inject faults,
 * just not into a grid that is feeding live decisions.
 */
export const POST = apiRoute<{ code: string }, SensorFaultInput>(
  { permission: 'twin.simulate', bodySchema: sensorFaultSchema, limit: 40 },
  async ({ params, body, user, request }) => {
    const result = await setSensorFault({
      sensorCode: params.code,
      faultKind: body.faultKind ?? null,
      mode: body.mode ?? 'demo',
    })

    if (!result.ok) {
      throw new ApiError(
        result.reason === 'not_found' ? ERROR_CODES.notFound : ERROR_CODES.conflict,
        { details: { reason: result.reason ?? 'refused', message: result.message } },
      )
    }

    await writeAudit({
      action: AUDIT_ACTIONS.sensorFaultInjected,
      entity: 'sensor',
      entityId: params.code,
      user,
      request,
      detail: `${body.faultKind ?? 'cleared'} in ${body.mode ?? 'demo'} mode`,
    })

    return result
  },
)
