import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { prisma } from "@/server/db";
import { UnauthorizedError } from "@/server/errors";
import { fail, ok, parseJson } from "@/server/http";
import { clientIp, createSessionTokens } from "@/server/security/auth";
import { setAuthCookies } from "@/server/security/cookies";
import { verifyPassword } from "@/server/security/password";
import { enforceRateLimit } from "@/server/security/rate-limit";

const loginSchema = z.object({
  email: z.string().email().transform((value) => value.toLowerCase()),
  password: z.string().min(1)
});

export async function POST(request: NextRequest) {
  const ipAddress = clientIp(request);
  const userAgent = request.headers.get("user-agent") ?? undefined;

  try {
    const input = await parseJson(request, loginSchema);
    await enforceRateLimit(`login:${ipAddress}:${input.email}`, 8, 60);

    const user = await prisma.user.findUnique({ where: { email: input.email } });
    const passwordOk = user ? await verifyPassword(input.password, user.passwordHash) : false;

    await prisma.loginEvent.create({
      data: {
        userId: user?.id,
        email: input.email,
        success: passwordOk,
        reason: passwordOk ? undefined : "invalid_credentials",
        ipAddress,
        userAgent
      }
    });

    if (!user || !passwordOk) {
      throw new UnauthorizedError("Invalid email or password");
    }

    if (user.status !== "ACTIVE") {
      throw new UnauthorizedError("Account is not active");
    }

    const tokens = await createSessionTokens({
      userId: user.id,
      roles: user.roles,
      ipAddress,
      userAgent
    });

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

    const response = ok({ user: { id: user.id, email: user.email, username: user.username, roles: user.roles } }) as NextResponse;
    setAuthCookies(response, tokens);
    return response;
  } catch (error) {
    return fail(error);
  }
}
