// tdd-guard:skip — Next.js route handler; die Privileg-Helfer (canManageUser)
// sind separat unit-getestet. Verhalten: ändert die Login-E-Mail eines Users,
// den der Aufrufer verwalten darf.
//
// KAR-831 (Security): vorher fehlte der canManageUser-Check — ein Admin konnte
// die E-Mail eines Masteradmins umbiegen und den Account per öffentlichem
// Passwort-Reset übernehmen. Jetzt analog reset-link/reset-password/invite:
// Ziel-Rolle laden + canManageUser-Gate, CSRF, Zod-Validierung.
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getUserSession, hasPermission, canManageUser, type RoleCode } from '@/lib/auth/permissions'
import { checkCsrf } from '@/lib/security'
import { createAdminClient } from '@/lib/supabase/admin'
import { createClient } from '@/lib/supabase/server'
import { notifyEmailChanged } from '@/lib/email/notifications'

const UpdateEmailBodySchema = z.object({
  userId: z.string().uuid(),
  newEmail: z.string().email().max(160),
})

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 })
  }
  if (!hasPermission(session, 'users.update_email')) {
    return NextResponse.json({ error: 'Missing permission: users.update_email' }, { status: 403 })
  }

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

  const supabase = await createClient()
  const adminClient = createAdminClient()

  const { data: profile } = await supabase
    .from('user_profiles')
    .select('auth_user_id, 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 change the email of a user they
  // cannot manage (e.g. an admin for a masteradmin). Mirrors reset-link/invite.
  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 { error: authError } = await adminClient.auth.admin.updateUserById(
    profile.auth_user_id as string,
    { email: newEmail }
  )

  if (authError) {
    return NextResponse.json({ error: authError.message }, { status: 500 })
  }

  await supabase
    .from('user_profiles')
    .update({ email: newEmail })
    .eq('id', userId)

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

  await notifyEmailChanged(newEmail, profile.email as string, newEmail)

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