import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { ApiError, ERROR_CODES } from '@/lib/api/errors'
import {
  approvalSchema,
  decisionExecuteSchema,
  type ApprovalRequest,
  type DecisionExecuteInput,
} from '@/lib/api/schemas'
import { decideApproval, executeDecision, getDecision } from '@/lib/services/decision-service'

export const dynamic = 'force-dynamic'

/**
 * Record an approval step (§13).
 *
 * The supervisor step needs its own permission: an operator approving their own
 * recommendation at both steps would make the second signature worthless, and the check
 * has to be on the server for the same reason every other one is (§34).
 */
export const POST = apiRoute<Record<string, string>, ApprovalRequest>(
  { permission: ['decisions.approve', 'decisions.supervise'], bodySchema: approvalSchema, limit: 40 },
  async ({ body, user, request }) => {
    const required = body.step === 'supervisor' ? 'decisions.supervise' : 'decisions.approve'
    if (!user.permissions.has(required)) throw new ApiError(ERROR_CODES.permissionDenied)

    const before = await getDecision(body.decisionCode)
    if (!before) throw new ApiError(ERROR_CODES.notFound)

    const status = await decideApproval({
      decisionCode: body.decisionCode,
      step: body.step,
      decision: body.decision,
      comment: body.comment,
      commentAr: body.commentAr,
      user: { id: user.id, name: user.name, nameAr: user.nameAr },
    })
    if (!status) throw new ApiError(ERROR_CODES.notFound)

    await writeAudit({
      action: body.decision === 'rejected' ? AUDIT_ACTIONS.decisionRejected : AUDIT_ACTIONS.decisionApproved,
      entity: 'decision',
      entityId: body.decisionCode,
      user,
      request,
      before: { status: before.status },
      after: { status, step: body.step, decision: body.decision },
      detail: `${body.step} ${body.decision}`,
    })

    return { code: body.decisionCode, status }
  },
)

/**
 * Carry out an approved decision — which, in this build, means simulating it (§43).
 *
 * The response says so explicitly, and so does the stored outcome, because the one thing
 * this platform must never do is let a reader believe a switching order was issued.
 */
export const PUT = apiRoute<Record<string, string>, DecisionExecuteInput>(
  { permission: 'decisions.approve', bodySchema: decisionExecuteSchema, limit: 20 },
  async ({ body, user, request }) => {
    const outcome = await executeDecision(body.decisionCode)
    if (!outcome) throw new ApiError(ERROR_CODES.notFound)

    await writeAudit({
      action: AUDIT_ACTIONS.decisionSimulated,
      entity: 'decision',
      entityId: body.decisionCode,
      user,
      request,
      detail: outcome.outcome,
    })

    return { code: body.decisionCode, executionIsSimulated: true, ...outcome }
  },
)
