import { NextRequest, NextResponse } from "next/server";

import { SESSION_COOKIE, UserRole, authenticateUser, getDefaultPathForRole, serializeSession } from "@/lib/auth";
import { getRequestAuditContext, writeAuditTrail } from "@/lib/audit";
import { consumeRateLimit, getRateLimitHeaders } from "@/lib/rate-limit";
import { prisma } from "@/lib/prisma";

function getSafePath(value: string | null) {
  if (!value) {
    return null;
  }

  if (!value.startsWith("/")) {
    return null;
  }

  return value;
}

function resolveNumber(raw: string | undefined, fallback: number) {
  const value = Number(raw?.trim());
  if (!Number.isInteger(value) || value <= 0) {
    return fallback;
  }

  return value;
}

export async function POST(request: NextRequest) {
  const { ipAddress, userAgent } = await getRequestAuditContext();
  const retryControl = consumeRateLimit(ipAddress || "unknown", {
    scope: "auth_login",
    limit: resolveNumber(process.env.LOGIN_RATE_LIMIT_ATTEMPTS, 10),
    windowMs: resolveNumber(process.env.LOGIN_RATE_LIMIT_WINDOW_MS, 15 * 60 * 1000)
  });

  if (!retryControl.allowed) {
    const loginUrl = new URL("/login", request.url);
    loginUrl.searchParams.set("error", "rate_limited");
    const response = NextResponse.redirect(loginUrl);
    const headers = getRateLimitHeaders(retryControl);
    Object.entries(headers).forEach(([headerName, headerValue]) => {
      response.headers.set(headerName, headerValue);
    });
    return response;
  }

  const form = await request.formData();
  const rawEmail = form.get("email");
  const rawPassword = form.get("password");
  const rawNext = form.get("next");

  const next = getSafePath(typeof rawNext === "string" ? rawNext : null);
  const email = typeof rawEmail === "string" ? rawEmail.trim() : "";
  const password = typeof rawPassword === "string" ? rawPassword : "";

  if (!email || !password) {
    const loginUrl = new URL("/login", request.url);
    loginUrl.searchParams.set("error", "credentials_required");
    if (next) {
      loginUrl.searchParams.set("next", next);
    }

    return NextResponse.redirect(loginUrl);
  }

  const session = await authenticateUser(email, password);
  if (!session) {
    const attemptedUser = await prisma.user.findUnique({
      where: { email },
      select: { id: true, tenantId: true, status: true }
    });

    if (attemptedUser) {
      await writeAuditTrail({
        tenantId: attemptedUser.tenantId,
        actorUserId: attemptedUser.id,
        entityType: "user",
        entityId: attemptedUser.id,
        action: "user_login_failed",
        metadata: {
          email,
          status: attemptedUser.status,
          source: "web"
        },
        ipAddress,
        userAgent
      });
    }

    const loginUrl = new URL("/login", request.url);
    loginUrl.searchParams.set("error", "invalid_credentials");
    if (next) {
      loginUrl.searchParams.set("next", next);
    }

    return NextResponse.redirect(loginUrl);
  }

  await prisma.user.update({
    where: { id: session.userId },
    data: { lastLoginAt: new Date() }
  });

  await writeAuditTrail({
    tenantId: session.tenantId,
    actorUserId: session.userId,
    entityType: "user",
    entityId: session.userId,
    action: "user_login",
    metadata: {
      email
    },
    ipAddress,
    userAgent
  });

  const destination = next ?? getDefaultPathForRole(session.role as UserRole);
  const response = NextResponse.redirect(new URL(destination, request.url));
  response.cookies.set(SESSION_COOKIE, await serializeSession(session), {
    httpOnly: true,
    sameSite: "lax",
    secure: process.env.NODE_ENV === "production",
    path: "/",
    maxAge: Math.max(1, Math.floor(session.expiresAt - Date.now() / 1000))
  });

  return response;
}
