// ── Auth: Login ──────────────────────────────────────────────────────────────
// POST /api/auth/login
// Authenticates a user with email/username + password and returns a JWT session
// cookie. Supports account lockout, credential validation, and login audit
// logging. Returns user data on success, error details on failure.

import { NextRequest } from "next/server"
import {
  comparePassword,
  getUserByEmail,
  getUserByUsername,
  mapDbUserToSessionUser,
  recordLoginAttempt,
  incrementFailedAttempts,
  resetFailedAttempts,
  isAccountLocked,
  createSession,
  setSessionContext,
  SESSION_COOKIE,
} from "@/lib/auth"

// ── Helpers ──────────────────────────────────────────────────────────────────

function jsonResponse(data: unknown, status: number) {
  return new Response(JSON.stringify(data), {
    status,
    headers: { "Content-Type": "application/json" },
  })
}

// ── POST ─────────────────────────────────────────────────────────────────────

export async function POST(request: NextRequest) {
  try {
    const { email, username, password } = await request.json()

    const credential = email || username

    // Validate that both credential and password are present
    if (!credential || !password) {
      return jsonResponse(
        { error: "Email/Username and password are required." },
        400
      )
    }

    // Reject empty strings (whitespace-only credentials)
    if (credential.trim().length === 0 || password.trim().length === 0) {
      return jsonResponse(
        { error: "Credentials cannot be empty." },
        400
      )
    }

    // Extract client IP from proxy headers for audit logging
    const ipAddress =
      request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
      request.headers.get("x-real-ip") ||
      "127.0.0.1"

    const userAgent = request.headers.get("user-agent") || null

    // Try to find user by email first, then by username
    let dbUser =
      email || credential.includes("@")
        ? await getUserByEmail(credential)
        : null

    if (!dbUser) {
      dbUser = await getUserByUsername(credential)
    }

    // If user does not exist, log attempt and return generic error
    if (!dbUser) {
      await recordLoginAttempt(
        null,
        credential,
        ipAddress,
        userAgent,
        false,
        "User not found"
      )
      return jsonResponse(
        { error: "Invalid email/username or password." },
        401
      )
    }

    // Check if account is temporarily locked due to too many failed attempts
    const lockStatus = await isAccountLocked(dbUser)
    if (lockStatus.locked) {
      await recordLoginAttempt(
        dbUser.id,
        credential,
        ipAddress,
        userAgent,
        false,
        lockStatus.reason
      )
      return jsonResponse(
        { error: lockStatus.reason },
        423
      )
    }

    // Verify password hash against stored hash
    const valid = await comparePassword(password, dbUser.password_hash)
    if (!valid) {
      await incrementFailedAttempts(dbUser.id)
      await recordLoginAttempt(
        dbUser.id,
        credential,
        ipAddress,
        userAgent,
        false,
        "Invalid password"
      )
      return jsonResponse(
        { error: "Invalid email/username or password." },
        401
      )
    }

    // Successful login: reset failure counter, log success, create session
    await resetFailedAttempts(dbUser.id)
    await recordLoginAttempt(
      dbUser.id,
      credential,
      ipAddress,
      userAgent,
      true
    )

    const token = await createSession(dbUser.id, dbUser.role_name)
    await setSessionContext(dbUser.id, ipAddress)

    const user = mapDbUserToSessionUser(dbUser)

    // Set HttpOnly session cookie with configurable Secure flag in production
    const cookieStr = `${SESSION_COOKIE}=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=86400${process.env.NODE_ENV === "production" ? "; Secure" : ""}`

    return new Response(JSON.stringify({ user }), {
      status: 200,
      headers: {
        "Content-Type": "application/json",
        "Set-Cookie": cookieStr,
      },
    })
  } catch (error) {
    console.error("Login error:", error)
    return new Response(
      JSON.stringify({ error: "Authentication service unavailable." }),
      { status: 503, headers: { "Content-Type": "application/json" } }
    )
  }
}
