import "server-only";

import { db } from "../db";
import { logger } from "../logger";
import { verifyAgainstDummy, verifyPassword } from "./password";
import { isLoginBlocked, recordLoginAttempt, purgeOldLoginAttempts } from "./rate-limit";
import { createSession, purgeExpiredSessions } from "./session";

export type LoginResult = { ok: true } | { ok: false; reason: "invalid" | "rate_limited" };

export function normalizeUsername(username: string): string {
  return username.trim().toLowerCase();
}

export async function login(rawUsername: string, password: string, ip: string): Promise<LoginResult> {
  const username = normalizeUsername(rawUsername);

  if (await isLoginBlocked(username, ip)) {
    logger.warn("auth.login.rate_limited", { username, ip });
    return { ok: false, reason: "rate_limited" };
  }

  const user = await db.user.findUnique({ where: { username } });
  const valid = user
    ? await verifyPassword(user.passwordHash, password)
    : await verifyAgainstDummy(password);

  await recordLoginAttempt(username, ip, valid);

  if (!user || !valid) {
    logger.warn("auth.login.failed", { username, ip });
    return { ok: false, reason: "invalid" };
  }

  await createSession(user.id);
  logger.info("auth.login.success", { username, ip });

  // Opportunistic housekeeping; never let it fail a login.
  void Promise.all([purgeExpiredSessions(), purgeOldLoginAttempts()]).catch((error) =>
    logger.error("auth.housekeeping.failed", { error }),
  );

  return { ok: true };
}
