/**
 * Override für Payload's native Login-Route
 *
 * POST /api/users/login
 *
 * Diese Route überschreibt den nativen Payload-Login-Endpoint, um fehlgeschlagene
 * Login-Versuche im Audit-Log zu erfassen. Dies ist notwendig, weil Payload
 * keinen nativen afterLoginFailed Hook hat.
 *
 * Security:
 * - Rate-Limiting: 5 Versuche pro 15 Minuten pro IP (Anti-Brute-Force)
 * - IP-Blocklist-Prüfung
 * - Audit-Logging für fehlgeschlagene Logins
 *
 * Erfolgreiche Logins werden weiterhin durch den afterLogin-Hook geloggt.
 */

import { getPayload } from 'payload'
import configPromise from '@payload-config'
import { NextRequest, NextResponse } from 'next/server'
import { logLoginFailed, logRateLimit } from '@/lib/audit/audit-service'
import {
  authLimiter,
  rateLimitHeaders,
  getClientIpFromRequest,
  isIpBlocked,
  validateCsrf,
} from '@/lib/security'

/**
 * Extrahiert Client-Informationen aus dem Request für Audit-Logging
 */
function getClientInfo(req: NextRequest): { ipAddress: string; userAgent: string } {
  const forwarded = req.headers.get('x-forwarded-for')
  const realIp = req.headers.get('x-real-ip')
  const ipAddress =
    (forwarded ? forwarded.split(',')[0]?.trim() : undefined) || realIp || 'unknown'

  const userAgent = req.headers.get('user-agent') || 'unknown'

  return { ipAddress, userAgent }
}

export async function POST(req: NextRequest): Promise<NextResponse> {
  // IP-Blocklist prüfen
  const clientIp = getClientIpFromRequest(req)
  if (isIpBlocked(clientIp)) {
    return NextResponse.json(
      { errors: [{ message: 'Access denied' }] },
      { status: 403 },
    )
  }

  // CSRF-Schutz für Browser-basierte Requests
  const csrfResult = validateCsrf(req)
  if (!csrfResult.valid) {
    return NextResponse.json(
      { errors: [{ message: 'CSRF validation failed' }] },
      { status: 403 },
    )
  }

  // Rate-Limiting prüfen (Anti-Brute-Force)
  const rateLimit = await authLimiter.check(clientIp)
  if (!rateLimit.allowed) {
    const payload = await getPayload({ config: configPromise })
    await logRateLimit(payload, '/api/users/login', undefined, undefined)

    return NextResponse.json(
      {
        errors: [
          {
            message: 'Too many login attempts. Please try again later.',
          },
        ],
      },
      {
        status: 429,
        headers: rateLimitHeaders(rateLimit, 5),
      },
    )
  }

  const payload = await getPayload({ config: configPromise })

  try {
    // Parse body - unterstütze JSON und FormData (Admin Panel sendet FormData)
    let email: string | undefined
    let password: string | undefined

    const contentType = req.headers.get('content-type') || ''

    // Für Browser-Formulare: Redirect-Ziel extrahieren
    let redirectUrl: string | undefined

    // Prüfen ob dies ein Browser-Formular ist (nicht XHR/fetch)
    const acceptHeader = req.headers.get('accept') || ''
    const isBrowserForm =
      acceptHeader.includes('text/html') && !req.headers.get('x-requested-with')

    if (contentType.includes('multipart/form-data')) {
      const formData = await req.formData()

      // Payload Admin Panel sendet Daten als _payload JSON-Feld
      const payloadField = formData.get('_payload')
      if (payloadField) {
        try {
          const payloadData = JSON.parse(payloadField.toString())
          email = payloadData.email
          password = payloadData.password
        } catch {
          // Falls _payload kein gültiges JSON ist, ignorieren
        }
      }

      // Fallback: Direkte FormData-Felder (für curl/Tests)
      if (!email || !password) {
        email = formData.get('email')?.toString()
        password = formData.get('password')?.toString()
      }

      // Redirect-URL für Browser-Formulare
      redirectUrl = formData.get('redirect')?.toString()
    } else if (contentType.includes('application/x-www-form-urlencoded')) {
      const formData = await req.formData()
      email = formData.get('email')?.toString()
      password = formData.get('password')?.toString()
      redirectUrl = formData.get('redirect')?.toString()
    } else {
      // Default: JSON
      const body = await req.json()
      email = body.email
      password = body.password
    }

    // Validierung
    if (!email || !password) {
      return NextResponse.json(
        {
          errors: [{ message: 'E-Mail und Passwort sind erforderlich' }],
        },
        { status: 400 },
      )
    }

    try {
      // Versuche Login über Payload
      const result = await payload.login({
        collection: 'users',
        data: {
          email,
          password,
        },
      })

      // Erfolgreicher Login - afterLogin Hook hat bereits geloggt

      // Für Browser-Formulare: Redirect mit gesetztem Cookie
      if (isBrowserForm && redirectUrl) {
        // Sicherheitscheck: Nur relative URLs oder URLs zur eigenen Domain erlauben
        const serverUrl = process.env.PAYLOAD_PUBLIC_SERVER_URL || ''
        const isRelativeUrl = redirectUrl.startsWith('/')
        const isSameDomain = serverUrl && redirectUrl.startsWith(serverUrl)

        if (isRelativeUrl || isSameDomain) {
          // Verhindere Redirect zu Login-Seite (Loop-Schutz)
          let safeRedirect = redirectUrl
          if (redirectUrl.includes('/login')) {
            safeRedirect = '/admin'
          }

          const redirectResponse = NextResponse.redirect(
            isRelativeUrl
              ? new URL(safeRedirect, req.url)
              : new URL(safeRedirect),
            302,
          )

          // Set the token cookie
          if (result.token) {
            redirectResponse.cookies.set('payload-token', result.token, {
              httpOnly: true,
              secure: process.env.NODE_ENV === 'production',
              sameSite: 'lax',
              path: '/',
              maxAge: result.exp ? result.exp - Math.floor(Date.now() / 1000) : 7200,
            })
          }

          return redirectResponse
        }
      }

      // Für API-Requests: JSON-Response im Payload-Format
      const response = NextResponse.json({
        message: 'Auth Passed',
        user: result.user,
        token: result.token,
        exp: result.exp,
      })

      // Set the token cookie (wie Payload es macht)
      if (result.token) {
        response.cookies.set('payload-token', result.token, {
          httpOnly: true,
          secure: process.env.NODE_ENV === 'production',
          sameSite: 'lax',
          path: '/',
          maxAge: result.exp ? result.exp - Math.floor(Date.now() / 1000) : 7200,
        })
      }

      return response
    } catch (loginError) {
      // Login fehlgeschlagen - Audit-Log erstellen mit vollem Request-Context
      const errorMessage =
        loginError instanceof Error ? loginError.message : 'Unbekannter Fehler'

      // Bestimme den Grund für das Fehlschlagen
      let reason = 'Unbekannter Fehler'
      if (errorMessage.includes('not found') || errorMessage.includes('incorrect')) {
        reason = 'Ungültige Anmeldedaten'
      } else if (errorMessage.includes('locked')) {
        reason = 'Konto gesperrt'
      } else if (errorMessage.includes('disabled')) {
        reason = 'Konto deaktiviert'
      } else if (errorMessage.includes('verify')) {
        reason = 'E-Mail nicht verifiziert'
      } else {
        reason = errorMessage
      }

      // Client-Info für Audit-Log extrahieren
      const clientInfo = getClientInfo(req)

      // Audit-Log für fehlgeschlagenen Login mit vollem Client-Context
      await logLoginFailed(payload, email, reason, clientInfo)

      console.log(
        `[Audit:Auth] Login failed for ${email}: ${reason} (IP: ${clientInfo.ipAddress})`,
      )

      // Für Browser-Formulare: Redirect zur Login-Seite mit Fehlermeldung
      if (isBrowserForm) {
        const loginUrl = new URL('/admin/login', req.url)
        loginUrl.searchParams.set('error', 'invalid')
        if (redirectUrl) {
          loginUrl.searchParams.set('redirect', redirectUrl)
        }
        return NextResponse.redirect(loginUrl, 302)
      }

      // Response im Payload-Format (wie der native Endpoint)
      return NextResponse.json(
        {
          errors: [
            {
              message: 'The email or password provided is incorrect.',
            },
          ],
        },
        { status: 401 },
      )
    }
  } catch (error) {
    console.error('[API:Auth] Login error:', error)
    return NextResponse.json(
      {
        errors: [{ message: 'Interner Serverfehler' }],
      },
      { status: 500 },
    )
  }
}
