/**
 * Custom Login Route mit Audit-Logging
 *
 * POST /api/users/login
 *
 * Diese Route erweitert Payload's native Login um:
 * - Audit-Logging für fehlgeschlagene Login-Versuche
 * - Rate-Limiting (Anti-Brute-Force)
 * - IP-Blocklist-Prüfung
 * - CSRF-Schutz für Browser-Requests
 *
 * Wichtig: Security-Checks laufen fail-closed.
 * Wenn ein Sicherheitsmodul nicht verfügbar ist oder ein Check fehlschlägt,
 * wird der Request abgelehnt.
 */

import { getPayload } from 'payload'
import config from '@payload-config'
import { NextRequest, NextResponse } from 'next/server'
import { authLimiter, runApiGuards } from '@/lib/security'

// Lazy import für Audit-Service
type AuditService = {
  logLoginFailed?: (
    payload: unknown,
    email: string,
    reason: string,
    clientInfo: { ipAddress: string; userAgent: string },
  ) => Promise<void>
  logRateLimit?: (
    payload: unknown,
    endpoint: string,
    userId?: number,
    tenantId?: number,
  ) => Promise<void>
}

let auditService: AuditService = {}
let auditServiceLoaded = false

async function getAuditService(): Promise<AuditService> {
  if (auditServiceLoaded) return auditService

  try {
    const audit = await import('@/lib/audit/audit-service')
    auditService = {
      logLoginFailed: audit.logLoginFailed as AuditService['logLoginFailed'],
      logRateLimit: audit.logRateLimit as AuditService['logRateLimit'],
    }
  } catch (err) {
    console.warn('[Login] Audit service not available:', err)
    auditService = {}
  }

  auditServiceLoaded = true

  return auditService
}

/**
 * Extrahiert Client-IP aus Request
 */
function getClientInfo(req: NextRequest, ipAddress: string): { ipAddress: string; userAgent: string } {
  return {
    ipAddress,
    userAgent: req.headers.get('user-agent') || 'unknown',
  }
}

export async function POST(req: NextRequest): Promise<NextResponse> {
  const guardResult = await runApiGuards(req, {
    endpoint: '/api/users/login',
    blocklistOnly: true,
    csrf: 'browser',
    rateLimiter: authLimiter,
    rateLimitMax: 5,
    onRateLimit: async () => {
      try {
        const payload = await getPayload({ config })
        const audit = await getAuditService()
        await audit.logRateLimit?.(payload, '/api/users/login', undefined, undefined)
      } catch {
        // Ignore audit logging errors
      }
    },
  })
  if (!guardResult.ok) {
    return guardResult.response
  }
  const clientIp = guardResult.ip

  // 4. Parse Request Body
  let email: string | undefined
  let password: string | undefined

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

    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
        }
      }
      // Fallback: Direkte FormData-Felder
      if (!email || !password) {
        email = formData.get('email')?.toString()
        password = formData.get('password')?.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()
    } else {
      // Default: JSON
      const body = await req.json()
      email = body.email
      password = body.password
    }
  } catch (err) {
    console.error('[Login] Failed to parse request body:', err)
    return NextResponse.json(
      { errors: [{ message: 'Invalid request body' }] },
      { status: 400 },
    )
  }

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

  // 6. Login durchführen
  try {
    const payload = await getPayload({ config })

    const result = await payload.login({
      collection: 'users',
      data: { email, password },
    })

    // Erfolgreicher Login - Response erstellen
    const response = NextResponse.json({
      message: 'Auth Passed',
      user: result.user,
      token: result.token,
      exp: result.exp,
    })

    // Cookie setzen
    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
    const errorMessage = loginError instanceof Error ? loginError.message : 'Unknown error'

    // 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
    }

    // Audit-Log für fehlgeschlagenen Login (optional, fail-safe)
    try {
      const payload = await getPayload({ config })
      const audit = await getAuditService()
      const clientInfo = getClientInfo(req, clientIp)
      await audit.logLoginFailed?.(payload, email, reason, clientInfo)
      console.log(`[Audit:Auth] Login failed for ${email}: ${reason} (IP: ${clientInfo.ipAddress})`)
    } catch (auditErr) {
      console.warn('[Login] Audit logging failed:', auditErr)
      // Continue - don't let audit failure affect response
    }

    // Standard Payload-Fehlerantwort
    return NextResponse.json(
      { errors: [{ message: 'The email or password provided is incorrect.' }] },
      { status: 401 },
    )
  }
}
