/**
 * Custom Login Endpoint mit Audit-Logging
 *
 * POST /api/auth/login
 *
 * Dieser Endpoint wrappet den nativen Payload-Login und loggt fehlgeschlagene
 * Login-Versuche im Audit-Log. Erfolgreiche Logins werden durch den
 * afterLogin-Hook in der Users-Collection geloggt.
 *
 * Security:
 * - Rate-Limiting: 5 Versuche pro 15 Minuten pro IP (Anti-Brute-Force)
 * - IP-Blocklist-Prüfung
 * - Audit-Logging für fehlgeschlagene Logins
 *
 * Body:
 * - email: string (erforderlich)
 * - password: string (erforderlich)
 */

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,
  runApiGuards,
} from '@/lib/security'
import {
  asObject,
  requiredString,
  validateJsonBody,
  validationErrorResponse,
  type ApiValidationResult,
} from '@/lib/validation'

/**
 * Extrahiert Client-Informationen aus dem Request für Audit-Logging
 */
function getClientInfo(req: NextRequest, ipAddress?: string): { ipAddress: string; userAgent: string } {
  const userAgent = req.headers.get('user-agent') || 'unknown'

  return { ipAddress: ipAddress || 'unknown', userAgent }
}

interface LoginBody {
  email: string
  password: string
}

function validateLoginBody(input: unknown): ApiValidationResult<LoginBody> {
  const objectResult = asObject(input)
  if (!objectResult.valid) {
    return objectResult as ApiValidationResult<LoginBody>
  }

  const emailResult = requiredString(objectResult.data, 'email')
  const passwordResult = requiredString(objectResult.data, 'password')

  if (!emailResult.valid || !passwordResult.valid) {
    return {
      valid: false,
      issues: [
        ...(emailResult.valid ? [] : emailResult.issues),
        ...(passwordResult.valid ? [] : passwordResult.issues),
      ],
    }
  }

  return {
    valid: true,
    data: {
      email: emailResult.data,
      password: passwordResult.data,
    },
  }
}

export async function POST(req: NextRequest): Promise<NextResponse> {
  try {
    const payload = await getPayload({ config: configPromise })
    const guardResult = await runApiGuards(req, {
      endpoint: '/api/auth/login',
      blocklistOnly: true,
      csrf: 'browser',
      rateLimiter: authLimiter,
      rateLimitMax: 5,
      onRateLimit: async () => {
        await logRateLimit(payload, '/api/auth/login', undefined, undefined)
      },
    })
    if (!guardResult.ok) {
      return guardResult.response
    }

    const bodyResult = await validateJsonBody(req, validateLoginBody)
    if (!bodyResult.valid) {
      return validationErrorResponse(bodyResult.issues)
    }

    const { email, password } = bodyResult.data

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

      if (!result.user) {
        throw new Error('Login returned no user')
      }

      // Erfolgreicher Login - afterLogin Hook hat bereits geloggt
      // Setze Cookie für die Session
      const response = NextResponse.json({
        success: true,
        user: {
          id: result.user.id,
          email: result.user.email,
        },
        message: 'Login erfolgreich',
      })

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

      return response
    } catch (loginError) {
      // Login fehlgeschlagen - Audit-Log erstellen mit vollem 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, guardResult.ip)

      // 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})`,
      )

      return NextResponse.json(
        {
          success: false,
          error: 'Anmeldung fehlgeschlagen',
          // Keine detaillierten Infos aus Sicherheitsgründen
        },
        { status: 401 },
      )
    }
  } catch (error) {
    console.error('[API:Auth] Login error:', error)
    return NextResponse.json(
      { error: 'Interner Serverfehler' },
      { status: 500 },
    )
  }
}

/**
 * GET /api/auth/login
 *
 * Gibt API-Dokumentation zurück.
 */
export async function GET(): Promise<NextResponse> {
  return NextResponse.json({
    endpoint: '/api/auth/login',
    method: 'POST',
    description: 'Login endpoint with audit logging for failed attempts',
    body: {
      email: 'string (required)',
      password: 'string (required)',
    },
    response: {
      success: {
        success: true,
        user: { id: 'number', email: 'string' },
        message: 'string',
      },
      error: {
        success: false,
        error: 'string',
      },
    },
    note: 'Successful logins are logged via afterLogin hook. Failed attempts are logged here.',
  })
}
