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 { hashPassword, verifyPassword } from "@/server/security/password";

const passwordSchema = z.object({
  currentPassword: z.string().min(1).max(128),
  newPassword: z.string().min(12).max(128)
});

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

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

    const samePassword = await verifyPassword(input.newPassword, user.passwordHash);
    if (samePassword) {
      throw new ConflictError("Le nouveau mot de passe doit être différent", "PASSWORD_REUSED");
    }

    const passwordHash = await hashPassword(input.newPassword);

    await prisma.$transaction(async (tx) => {
      await tx.user.update({
        where: { id: user.id },
        data: { passwordHash }
      });
      await tx.session.updateMany({
        where: {
          userId: user.id,
          id: { not: session.id },
          revokedAt: null
        },
        data: { revokedAt: new Date() }
      });
      await writeAuditLog(
        {
          actorUserId: user.id,
          action: "account.password.update",
          entityType: "User",
          entityId: user.id,
          ipAddress: clientIp(request),
          userAgent: request.headers.get("user-agent") ?? undefined,
          metadata: { revokedOtherSessions: true } as Prisma.InputJsonValue
        },
        tx
      );
    });

    return ok({ updated: true });
  } catch (error) {
    return fail(error);
  }
}
