import { NextRequest } from "next/server";
import { Prisma } from "@prisma/client";
import { z } from "zod";
import { writeAuditLog } from "@/server/audit";
import { prisma } from "@/server/db";
import { ConflictError, UnauthorizedError } from "@/server/errors";
import { fail, ok, parseJson } from "@/server/http";
import { clientIp, requireUser } from "@/server/security/auth";
import { verifyPassword } from "@/server/security/password";

const emailSchema = z.object({
  email: z.string().email().max(254).transform((value) => value.trim().toLowerCase()),
  currentPassword: z.string().min(1).max(128)
});

export async function POST(request: NextRequest) {
  try {
    const { user } = await requireUser(request);
    const input = await parseJson(request, emailSchema);
    const passwordOk = await verifyPassword(input.currentPassword, user.passwordHash);

    if (!passwordOk) {
      throw new UnauthorizedError("Mot de passe actuel incorrect");
    }

    if (input.email !== user.email) {
      const existingUser = await prisma.user.findUnique({ where: { email: input.email }, select: { id: true } });
      if (existingUser && existingUser.id !== user.id) {
        throw new ConflictError("Cette adresse email est déjà utilisée", "EMAIL_ALREADY_USED");
      }

      await prisma.$transaction(async (tx) => {
        await tx.user.update({
          where: { id: user.id },
          data: { email: input.email, emailVerifiedAt: null }
        });
        await writeAuditLog(
          {
            actorUserId: user.id,
            action: "account.email.update",
            entityType: "User",
            entityId: user.id,
            ipAddress: clientIp(request),
            userAgent: request.headers.get("user-agent") ?? undefined,
            before: { email: user.email } as Prisma.InputJsonValue,
            after: { email: input.email } as Prisma.InputJsonValue
          },
          tx
        );
      });
    }

    return ok({ email: input.email });
  } catch (error) {
    return fail(error);
  }
}
