import "server-only"

import { eq } from "drizzle-orm"

import { PASSWORD_RULES } from "@/shared/lib/password-policy"

/**
 * Password security DB operations.
 *
 * These functions operate on the `password_security` table to track
 * failed-login counters and account lockout state. They receive `db`
 * and the `passwordSecurity` schema object as parameters so the caller
 * (NextAuth `authorize` callback) can share a single dynamic-import
 * resolution with its own DB access.
 */

/**
 * Get or create a password_security row for a user.
 */
export const getOrCreatePasswordSecurity = async (
  db: typeof import("@/shared/db")["db"],
  passwordSecurity: typeof import("@/shared/db/schema")["passwordSecurity"],
  userId: string
) => {
  const [existing] = await db
    .select()
    .from(passwordSecurity)
    .where(eq(passwordSecurity.userId, userId))
    .limit(1)

  if (existing) return existing

  const { createId } = await import("@paralleldrive/cuid2")
  const id = createId()
  await db.insert(passwordSecurity).values({
    id,
    userId,
    failedLoginAttempts: 0,
  })
  const [created] = await db
    .select()
    .from(passwordSecurity)
    .where(eq(passwordSecurity.userId, userId))
    .limit(1)
  return created
}

/**
 * Increment failed login attempts and lock the account if the threshold
 * is reached.
 */
export const recordFailedLogin = async (
  db: typeof import("@/shared/db")["db"],
  passwordSecurity: typeof import("@/shared/db/schema")["passwordSecurity"],
  userId: string
): Promise<{ locked: boolean; lockedUntil: Date | null }> => {
  const current = await getOrCreatePasswordSecurity(db, passwordSecurity, userId)
  const nextAttempts = current.failedLoginAttempts + 1
  const shouldLock = nextAttempts >= PASSWORD_RULES.maxLoginAttempts
  const lockedUntil = shouldLock
    ? new Date(Date.now() + PASSWORD_RULES.lockoutDurationMinutes * 60 * 1000)
    : null

  await db
    .update(passwordSecurity)
    .set({
      failedLoginAttempts: nextAttempts,
      lockedUntil,
      updatedAt: new Date(),
    })
    .where(eq(passwordSecurity.userId, userId))

  return { locked: shouldLock, lockedUntil }
}

/**
 * Reset failed login attempts on successful login.
 */
export const resetFailedLogin = async (
  db: typeof import("@/shared/db")["db"],
  passwordSecurity: typeof import("@/shared/db/schema")["passwordSecurity"],
  userId: string
): Promise<void> => {
  const current = await getOrCreatePasswordSecurity(db, passwordSecurity, userId)
  if (current.failedLoginAttempts === 0 && !current.lockedUntil) return
  await db
    .update(passwordSecurity)
    .set({
      failedLoginAttempts: 0,
      lockedUntil: null,
      updatedAt: new Date(),
    })
    .where(eq(passwordSecurity.userId, userId))
}
