import { sql } from "@/lib/db";
import { MAX_CODE_ATTEMPTS, codeMatches } from "@/lib/otp";
import { hashPassword } from "@/lib/password";
import { issueSession, toProfile } from "@/lib/users";

export async function POST(req: Request) {
  const { email, code, password } = await req.json();

  if (!email?.trim() || !/^\d{6}$/.test(code ?? "")) {
    return Response.json(
      { error: "Email and a 6-digit code are required." },
      { status: 400 },
    );
  }

  if (typeof password !== "string" || password.length < 8) {
    return Response.json(
      { error: "Password must be at least 8 characters." },
      { status: 400 },
    );
  }

  const normalized = email.trim().toLowerCase();

  try {
    // Charge the attempt before comparing so concurrent guesses can't race
    // past the cap, and so a correct guess still costs one of the five.
    const attempts = await sql<{ code_hash: string; attempts: number }>`
      UPDATE password_reset_codes
      SET attempts = attempts + 1
      WHERE email = ${normalized} AND expires_at > CURRENT_TIMESTAMP
      RETURNING code_hash, attempts
    `;

    const record = attempts[0];

    if (
      !record ||
      record.attempts > MAX_CODE_ATTEMPTS ||
      !codeMatches(record.code_hash, normalized, code)
    ) {
      return Response.json(
        { error: "Invalid or expired reset code." },
        { status: 400 },
      );
    }

    // A successful reset also proves control of the mailbox, so verify it too.
    const rows = await sql<{
      id: string;
      name: string;
      email: string;
      role: string | null;
    }>`
      UPDATE users
      SET password_hash = ${hashPassword(password)}, email_verified = TRUE
      WHERE email = ${normalized}
      RETURNING id, name, email, role
    `;

    const user = rows[0];

    if (!user) {
      return Response.json({ error: "User not found." }, { status: 404 });
    }

    await sql`DELETE FROM password_reset_codes WHERE email = ${normalized}`;

    const session = issueSession(user);

    return Response.json({
      data: { token: session.token, user: toProfile(user) },
    });
  } catch (error) {
    console.error("[RESET_PASSWORD]: ", error);
    return Response.json({ error: "Internal Server Error" }, { status: 500 });
  }
}
