import { prisma } from '@/lib/db'
import { AUDIT_ACTIONS, writeAudit } from '@/lib/audit'
import { apiRoute } from '@/lib/api/handler'
import { ApiError, ERROR_CODES } from '@/lib/api/errors'
import { alertActionSchema, type AlertActionInput } from '@/lib/api/schemas'

export const dynamic = 'force-dynamic'

const PERMISSION_FOR: Record<AlertActionInput['action'], string> = {
  acknowledge: 'alerts.acknowledge',
  assign: 'alerts.assign',
  resolve: 'alerts.resolve',
  close: 'alerts.resolve',
}

/**
 * Move an alert through its lifecycle.
 *
 * The permission required depends on the action, not on the route, so acknowledging is
 * available to more roles than resolving. Every transition is audited with the previous
 * status, which is what makes the alert history reconstructable after the fact.
 */
export const PATCH = apiRoute<{ id: string }, AlertActionInput>(
  {
    permission: ['alerts.acknowledge', 'alerts.assign', 'alerts.resolve'],
    bodySchema: alertActionSchema,
  },
  async ({ params, body, user, request }) => {
    const alert = await prisma.alert.findUnique({
      where: { id: params.id },
      include: { asset: { select: { code: true } } },
    })
    if (!alert) throw new ApiError(ERROR_CODES.notFound)

    if (!user.permissions.has(PERMISSION_FOR[body.action])) {
      throw new ApiError(ERROR_CODES.permissionDenied)
    }

    const now = new Date()
    let data: Record<string, unknown>
    let auditAction: string

    switch (body.action) {
      case 'acknowledge': {
        if (alert.status !== 'new') throw new ApiError(ERROR_CODES.duplicateSubmission)
        data = {
          status: 'acknowledged',
          acknowledgedById: user.id,
          acknowledgedAt: now,
          assignedToId: alert.assignedToId ?? user.id,
        }
        auditAction = AUDIT_ACTIONS.alertAcknowledged
        break
      }
      case 'assign': {
        if (!body.assigneeId) throw new ApiError(ERROR_CODES.validationFailed, {
          details: { assigneeId: 'An assignee is required.' },
        })
        const assignee = await prisma.user.findUnique({ where: { id: body.assigneeId } })
        if (!assignee) throw new ApiError(ERROR_CODES.notFound)
        data = { assignedToId: assignee.id, status: alert.status === 'new' ? 'acknowledged' : alert.status }
        auditAction = AUDIT_ACTIONS.alertAssigned
        break
      }
      case 'resolve':
      case 'close': {
        if (alert.status === 'resolved' || alert.status === 'closed') {
          throw new ApiError(ERROR_CODES.duplicateSubmission)
        }
        data = {
          status: body.action === 'close' ? 'closed' : 'resolved',
          resolvedAt: now,
          resolution: body.resolution ?? null,
          resolutionAr: body.resolutionAr ?? body.resolution ?? null,
        }
        auditAction = AUDIT_ACTIONS.alertResolved
        break
      }
    }

    const updated = await prisma.alert.update({ where: { id: alert.id }, data })

    await writeAudit({
      action: auditAction,
      entity: 'alert',
      entityId: alert.id,
      user,
      request,
      before: { status: alert.status, assignedToId: alert.assignedToId },
      after: { status: updated.status, assignedToId: updated.assignedToId },
      detail: `${alert.code}${alert.asset ? ` on ${alert.asset.code}` : ''}`,
    })

    return {
      id: updated.id,
      status: updated.status,
      acknowledgedAt: updated.acknowledgedAt,
      resolvedAt: updated.resolvedAt,
    }
  },
)
