import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { ApiError, ERROR_CODES } from '@/lib/api/errors'
import { physicsValidateSchema, type PhysicsValidateInput } from '@/lib/api/schemas'
import { toPerturbation } from '@/lib/api/overlay'
import { loadConstraints, validateActions } from '@/lib/services/physics-service'

export const dynamic = 'force-dynamic'

/** The engineering limits the validator applies (§10, §12). */
export const GET = apiRoute({ permission: 'physics.read' }, async () => {
  const constraints = await loadConstraints()
  return {
    constraints: constraints.map((constraint) => ({
      code: constraint.code,
      kind: constraint.kind,
      scopeKind: constraint.scopeKind,
      scopeCode: constraint.scopeCode,
      label: constraint.label,
      labelAr: constraint.labelAr,
      comparator: constraint.comparator,
      limitValue: constraint.limitValue,
      warnValue: constraint.warnValue,
      unit: constraint.unit,
      severity: constraint.severity,
    })),
    source: 'demo_model',
  }
})

/**
 * Validate a proposed set of actions (§11).
 *
 * A rejection is a 200 carrying a rejected verdict, not an error status: the request was
 * well-formed and the answer is "no, and here is the constraint that says so". Returning
 * a 4xx would make a legitimate engineering answer look like a client mistake.
 */
export const POST = apiRoute<Record<string, string>, PhysicsValidateInput>(
  { permission: 'physics.validate', bodySchema: physicsValidateSchema, limit: 40 },
  async ({ body, user, request }) => {
    const outcome = await validateActions({
      assetCode: body.assetCode,
      actions: body.actions,
      perturbation: toPerturbation(body.overlay),
      persist: body.persist,
      userId: user.id,
    })
    if (!outcome) throw new ApiError(ERROR_CODES.notFound)

    await writeAudit({
      action: AUDIT_ACTIONS.physicsValidated,
      entity: 'asset',
      entityId: body.assetCode,
      user,
      request,
      detail: `${outcome.verdict}: ${outcome.checks.length} checks, ${outcome.failed.length} failed`,
    })

    return outcome
  },
)
