"use server";

import { headers } from "next/headers";
import { eq } from "drizzle-orm";
import { z } from "zod";
import { db } from "@/lib/db/client";
import { users } from "@/lib/db/schema";
import { issueResetToken } from "@/lib/auth/reset-token";
import { sendTemplatedEmail } from "@/lib/email/send";
import { loadEnv } from "@/lib/env";
import { ipFromHeaders, rateLimitAsync } from "@/lib/rate-limit";

export type ForgotPasswordState = {
  ok: boolean;
  message?: string;
};

const schema = z.object({ email: z.string().email() });

/**
 * Always returns success to avoid leaking which emails are registered.
 * If the email matches an active account, a reset link is sent; otherwise
 * we silently do nothing.
 */
export async function requestPasswordReset(
  _prev: ForgotPasswordState,
  formData: FormData,
): Promise<ForgotPasswordState> {
  const ip = ipFromHeaders(await headers());
  const limit = await rateLimitAsync({
    key: `pwreset:${ip}`,
    max: 5,
    windowMs: 60 * 60 * 1000,
  });
  if (!limit.ok) {
    return {
      ok: false,
      message: "Too many reset requests. Please try again later.",
    };
  }

  const parsed = schema.safeParse({ email: formData.get("email") });
  if (!parsed.success) {
    return { ok: false, message: "Enter a valid email address." };
  }

  const [user] = await db
    .select({
      id: users.id,
      name: users.name,
      email: users.email,
      status: users.status,
    })
    .from(users)
    .where(eq(users.email, parsed.data.email.toLowerCase()))
    .limit(1);

  // Per-email throttle to prevent targeted spamming.
  await rateLimitAsync({
    key: `pwreset:email:${parsed.data.email.toLowerCase()}`,
    max: 3,
    windowMs: 60 * 60 * 1000,
  });

  if (user && user.status === "active") {
    const env = loadEnv();
    const { token, expiresAt } = await issueResetToken(user.id, {
      issuedBy: "self",
      ttlMinutes: 60,
    });
    const resetUrl = `${env.nextAuthUrl}/reset-password/${token}`;
    const expiresInMinutes = Math.round((expiresAt.getTime() - Date.now()) / 60_000);
    try {
      await sendTemplatedEmail({
        to: user.email,
        templateSlug: "password-reset",
        variables: {
          name: user.name,
          resetUrl,
          expiresInMinutes,
        },
      });
    } catch (err) {
      console.error("[forgot-password] failed to send email", err);
    }
  }

  return {
    ok: true,
    message:
      "If that email is registered, a reset link is on its way. Check your inbox.",
  };
}
