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(`aff-login:${ipAddress}:${input.email}`, 8, 60);

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

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

    if (!user || !passwordOk) {
      throw new UnauthorizedError("Identifiants invalides");
    }

    if (!user.affiliateAccount) {
      throw new UnauthorizedError("Compte affilié introuvable");
    }

    if (user.status !== "ACTIVE") {
      throw new UnauthorizedError("Compte inactif");
    }

    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 },
      account: { id: user.affiliateAccount.id, status: user.affiliateAccount.status }
    }) as NextResponse;
    setAuthCookies(response, tokens);
    return response;
  } catch (error) {
    return fail(error);
  }
}
