// tdd-guard:skip — Next.js route handler; pure helpers (generateRecoveryLink,
// canManageUser) are unit-tested separately. Behaviour: send a secure login link.
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getUserSession, canManageUser, type RoleCode } from '@/lib/auth/permissions'
import { checkCsrf } from '@/lib/security'
import { createClient } from '@/lib/supabase/server'
import { generateRecoveryLink } from '@/lib/auth/recovery-link'
import { notifyInvitation } from '@/lib/email/notifications'
import { routeError } from '@/lib/api/error'

const InviteBodySchema = z.object({
  userId: z.string().uuid(),
})

export async function POST(request: NextRequest) {
  const csrf = checkCsrf(request); if (csrf) return csrf
  const session = await getUserSession()
  if (!session) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }
  if (session.role !== 'admin' && session.role !== 'masteradmin') {
    return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
  }

  const parsed = InviteBodySchema.safeParse(await request.json().catch(() => ({})))
  if (!parsed.success) {
    return NextResponse.json({ error: 'Invalid body', issues: parsed.error.issues }, { status: 400 })
  }
  const { userId } = parsed.data

  const supabase = await createClient()

  const { data: profile } = await supabase
    .from('user_profiles')
    .select('email, roles ( code )')
    .eq('id', userId)
    .single()

  if (!profile) {
    return NextResponse.json({ error: 'User not found' }, { status: 404 })
  }

  // Backend privilege check — an admin must not invite a user they cannot manage.
  const targetRoleCode = ((Array.isArray(profile.roles) ? (profile.roles as { code: string }[])[0] : (profile.roles as { code: string } | null))?.code ?? 'readonly') as RoleCode
  if (!canManageUser(session, targetRoleCode)) {
    return NextResponse.json({ error: 'Insufficient privileges' }, { status: 403 })
  }

  const email = profile.email as string

  // KAR-772: the link points at /auth/confirm, which redeems the token on an
  // explicit user click (mail-security prefetch can't consume it) and lands the
  // now-authenticated invited user on the change-password page to set a password.
  const { origin } = new URL(request.url)
  const link = await generateRecoveryLink(email, origin, '/auth/change-password')
  if (!link) {
    return routeError('Einladungs-Link konnte nicht erzeugt werden.', null)
  }

  await notifyInvitation(email, link)

  await supabase.from('user_audit_log').insert({
    actor_id:       session.authUserId,
    target_user_id: userId,
    action:         'user.invitation_sent',
    details:        {},
  })

  return NextResponse.json({ ok: true })
}
