import { randomBytes } from "node:crypto";
import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";
import { hashPassword, verifyPassword } from "@/lib/auth";
import { logAudit } from "@/lib/audit";
import { ApiError } from "@/lib/auth";
import { handleApiError } from "@/lib/api-helpers";

const attempts = new Map<string, { count: number; startedAt: number }>();
const WINDOW_MS = 15 * 60 * 1000;
const MAX_ATTEMPTS = 5;

function normalizePhone(value: unknown): string {
  return typeof value === "string" ? value.replace(/[\s()-]/g, "") : "";
}

export async function POST(req: NextRequest) {
  try {
    const body = await req.json() as Record<string, unknown>;
    const phone = normalizePhone(body.phone);
    const code = typeof body.recoveryCode === "string" ? body.recoveryCode.trim().toUpperCase() : "";
    const password = typeof body.password === "string" ? body.password : "";
    if (!/^\+?[0-9]{7,15}$/.test(phone) || code.length < 24 || password.length < 12 || Buffer.byteLength(password, "utf8") > 72) {
      throw new ApiError("تحقق من رقم الهاتف ورمز الاسترداد، واستخدم كلمة مرور من 12 حرفاً على الأقل", 400);
    }

    const key = `${req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "local"}:${phone}`;
    const now = Date.now();
    const prior = attempts.get(key);
    if (prior && now - prior.startedAt < WINDOW_MS && prior.count >= MAX_ATTEMPTS) {
      throw new ApiError("محاولات كثيرة. انتظر 15 دقيقة ثم حاول مجدداً", 429);
    }
    if (!prior || now - prior.startedAt >= WINDOW_MS) attempts.set(key, { count: 1, startedAt: now });
    else attempts.set(key, { ...prior, count: prior.count + 1 });

    const matchingUsers = await db.user.findMany({
      where: { phone, isActive: true, deletedAt: null, recoveryCodeHash: { not: null } },
      select: { id: true, phone: true, recoveryCodeHash: true },
      take: 2,
    });
    const user = matchingUsers.length === 1 ? matchingUsers[0] : null;
    if (!user?.recoveryCodeHash || !(await verifyPassword(code, user.recoveryCodeHash))) {
      await logAudit(null, { action: "RECOVERY_FAILED", entity: "Auth", details: "محاولة استرداد كلمة مرور غير ناجحة" });
      throw new ApiError("تعذر التحقق من بيانات الاسترداد", 400);
    }

    const newPasswordHash = await hashPassword(password);
    const nextRecoveryCode = randomBytes(16).toString("hex").toUpperCase();
    const nextRecoveryCodeHash = await hashPassword(nextRecoveryCode);
    const changed = await db.user.updateMany({
      where: { id: user.id, recoveryCodeHash: user.recoveryCodeHash, isActive: true, deletedAt: null },
      data: { passwordHash: newPasswordHash, recoveryCodeHash: nextRecoveryCodeHash, passwordChangedAt: new Date() },
    });
    if (changed.count !== 1) throw new ApiError("رمز الاسترداد استُخدم أو تغير. أعد المحاولة بالرمز الجديد", 409);

    attempts.delete(key);
    await logAudit({ id: user.id, username: "", fullName: "استرداد حساب", role: "STAFF" }, {
      action: "PASSWORD_RECOVERED", entity: "User", entityId: user.id, details: "إعادة تعيين كلمة المرور باستخدام رمز الاسترداد",
    });
    return NextResponse.json({ success: true, recoveryCode: nextRecoveryCode });
  } catch (err) {
    return handleApiError(err);
  }
}
