"use server";

import { AuthError } from "next-auth";
import { headers } from "next/headers";
import { redirect, unstable_rethrow } from "next/navigation";
import { signIn } from "@/core/auth/auth";
import {
  assertLoginAllowed,
  clearLoginFailures,
  recordLoginFailure,
} from "@/core/auth/login-throttle";
import { getPostLoginPathForEmail } from "@/core/auth/post-login";

export type LoginActionResult =
  | { ok: true; redirectTo: string }
  | { ok: false; error: string };

const AUTH_ENTRY = "/?auth=login";

/**
 * Server-side credentials login with basic throttle.
 * Sets the session cookie via Auth.js, then redirects in this same action.
 */
export async function loginAction(
  email: string,
  password: string,
): Promise<LoginActionResult> {
  const normalizedEmail = email.trim().toLowerCase();
  const h = await headers();
  const ip =
    h.get("x-forwarded-for")?.split(",")[0]?.trim() ||
    h.get("x-real-ip") ||
    "unknown";
  const throttleKey = `${ip}:${normalizedEmail}`;

  const gate = assertLoginAllowed(throttleKey);
  if (!gate.ok) {
    return {
      ok: false,
      error: `Too many sign-in attempts. Try again in ${gate.retryAfterSec}s.`,
    };
  }

  const redirectTo = await getPostLoginPathForEmail(normalizedEmail);
  const destination =
    redirectTo === "/login" || redirectTo === AUTH_ENTRY
      ? "/dashboard"
      : redirectTo;

  try {
    const outcome = await signIn("credentials", {
      email: normalizedEmail,
      password,
      redirectTo: destination,
      redirect: false,
    });

    if (typeof outcome === "string" && /[?&]error=/.test(outcome)) {
      recordLoginFailure(throttleKey);
      return { ok: false, error: "Invalid email or password." };
    }
  } catch (error) {
    unstable_rethrow(error);

    if (error instanceof AuthError) {
      recordLoginFailure(throttleKey);
      return { ok: false, error: "Invalid email or password." };
    }

    recordLoginFailure(throttleKey);
    return { ok: false, error: "Invalid email or password." };
  }

  clearLoginFailures(throttleKey);
  redirect(destination);
}
