"use server";

import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { eq, sql } from "drizzle-orm";
import { db } from "@/lib/db/client";
import { users } from "@/lib/db/schema";
import {
  consumeResetToken,
  invalidateUserResetTokens,
} from "@/lib/auth/reset-token";
import { assessPasswordStrength, hashPassword } from "@/lib/auth/password";
import { sendTemplatedEmail } from "@/lib/email/send";
import { ipFromHeaders, rateLimitAsync } from "@/lib/rate-limit";
import { logAdminAction } from "@/lib/audit";

export type ResetPasswordState = {
  ok: boolean;
  fieldErrors?: Record<string, string[]>;
  message?: string;
};

export async function resetPassword(
  token: string,
  _prev: ResetPasswordState,
  formData: FormData,
): Promise<ResetPasswordState> {
  const ip = ipFromHeaders(await headers());
  const limit = await rateLimitAsync({
    key: `pwreset-submit:${ip}`,
    max: 10,
    windowMs: 60 * 60 * 1000,
  });
  if (!limit.ok) {
    return {
      ok: false,
      message: "Too many reset attempts. Please try again later.",
    };
  }

  const password = String(formData.get("password") ?? "");
  const confirm = String(formData.get("confirm") ?? "");
  if (password !== confirm) {
    return {
      ok: false,
      fieldErrors: { confirm: ["Passwords do not match."] },
    };
  }
  const issues = assessPasswordStrength(password);
  if (issues.length > 0) {
    return { ok: false, fieldErrors: { password: issues } };
  }

  const userId = await consumeResetToken(token);
  if (!userId) {
    return {
      ok: false,
      message: "This reset link is invalid or has expired. Request a new one.",
    };
  }

  const passwordHash = await hashPassword(password);
  await db
    .update(users)
    .set({
      passwordHash,
      tokenVersion: sql`${users.tokenVersion} + 1`,
    })
    .where(eq(users.id, userId));
  // Any other outstanding tokens for this user are now redundant.
  await invalidateUserResetTokens(userId);

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

  if (user) {
    try {
      await sendTemplatedEmail({
        to: user.email,
        templateSlug: "password-changed",
        variables: {
          name: user.name,
          changedAt: new Date().toUTCString(),
        },
      });
    } catch (err) {
      console.error("[reset-password] confirmation email failed", err);
    }
  }

  await logAdminAction({
    adminUserId: userId,
    action: "password_reset_self",
    targetId: userId,
  });

  redirect("/login?reset=1");
}
