import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getSessionUser } from '@/lib/auth'
import { clientIp } from '@/lib/security/rate-limit'
import { beginMfaEnrollment, confirmMfaEnrollment, disableMfa, getMfaState, regenerateRecoveryCodes } from '@/lib/security/mfa'

/**
 * Two-factor authentication for the signed-in account (2026-09-22).
 *   GET                → state
 *   POST { op: 'begin' }                 → secret + QR (not active yet)
 *   POST { op: 'confirm', code }         → enabled; recovery codes shown once
 *   POST { op: 'disable', code }         → off (needs a current code)
 *   POST { op: 'recovery', code }        → new recovery codes (needs a current code)
 * A pilot role switch never counts: only the account that actually signed in may change its own MFA.
 */
const schema = z.discriminatedUnion('op', [
  z.object({ op: z.literal('begin') }),
  z.object({ op: z.literal('confirm'), code: z.string().trim().min(6).max(12) }),
  z.object({ op: z.literal('disable'), code: z.string().trim().min(6).max(20) }),
  z.object({ op: z.literal('recovery'), code: z.string().trim().min(6).max(20) }),
])

export async function GET() {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })
  return NextResponse.json(await getMfaState(user.id))
}

export async function POST(req: NextRequest) {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })
  if (user.originId !== user.id) return NextResponse.json({ error: 'Switch back to your own account to change two-factor settings.' }, { status: 403 })
  const parsed = schema.safeParse(await req.json().catch(() => ({})))
  if (!parsed.success) return NextResponse.json({ error: 'Invalid request.' }, { status: 400 })
  const input = parsed.data
  const ip = clientIp(req.headers)
  const me = { id: user.id, email: user.email, label: user.name || user.email }
  const r =
    input.op === 'begin' ? await beginMfaEnrollment(me)
    : input.op === 'confirm' ? await confirmMfaEnrollment(me, input.code, ip)
    : input.op === 'disable' ? await disableMfa(me, input.code, ip)
    : await regenerateRecoveryCodes(me, input.code, ip)
  return r.ok ? NextResponse.json(r) : NextResponse.json({ error: r.error }, { status: 400 })
}
