/**
 * Per-email failed-login tracker with sliding-window lockout.
 *
 * audit3-followup (2026-05-29): backed by MySQL via BruteForceCounter so
 * state survives restarts. The original in-memory implementation lost
 * every counter on a process restart — a deploy or OOM-kill would reset
 * an in-progress brute-force. See [docs/audit-2-followups.md] and
 * src/lib/auth/brute-force-counter.ts for the model + design.
 *
 * Public API preserves the old signatures but is now async. NextAuth's
 * authorize callback and every API caller already runs in async context
 * so the only change at the callsite is the addition of `await`.
 *
 * Defence in depth: the middleware-level limit at src/proxy.ts
 * (5 attempts/hour per IP on /api/auth/callback/credentials) stays in
 * place; this module adds a per-email gate that fires inside the
 * NextAuth `authorize` callback. Both layers are independent.
 */
import {
    isLocked as bfcIsLocked,
    recordFailure as bfcRecordFailure,
    recordSuccess as bfcRecordSuccess,
    type LockStatus,
    type CounterConfig,
} from './brute-force-counter';
import { prisma } from '@/lib/prisma';

export type { LockStatus } from './brute-force-counter';

const BUCKET = 'login';

const DEFAULTS: CounterConfig = {
    maxFailures: 5,
    windowMs: 15 * 60 * 1000,
    lockoutMs: 15 * 60 * 1000,
};

export interface LoginAttemptsConfig {
    maxFailures?: number;
    windowMs?: number;
    lockoutMs?: number;
}

function resolveConfig(cfg: LoginAttemptsConfig): CounterConfig {
    return {
        maxFailures: cfg.maxFailures ?? DEFAULTS.maxFailures,
        windowMs: cfg.windowMs ?? DEFAULTS.windowMs,
        lockoutMs: cfg.lockoutMs ?? DEFAULTS.lockoutMs,
    };
}

function normalize(email: string): string {
    return email.trim().toLowerCase();
}

/** Inspect lock state without mutating it. Expired locks are cleared lazily. */
export async function isLocked(email: string, cfg: LoginAttemptsConfig = {}): Promise<LockStatus> {
    return bfcIsLocked(BUCKET, normalize(email), resolveConfig(cfg));
}

/** Count one failed authentication attempt. Locks the account if the threshold is hit. */
export async function recordFailure(email: string, cfg: LoginAttemptsConfig = {}): Promise<void> {
    return bfcRecordFailure(BUCKET, normalize(email), resolveConfig(cfg));
}

/** Clear all state for this email — call after a successful authentication. */
export async function recordSuccess(email: string): Promise<void> {
    return bfcRecordSuccess(BUCKET, normalize(email));
}

/** Test-only: drop all state in this bucket. */
export async function _resetForTests(): Promise<void> {
    await prisma.bruteForceCounter.deleteMany({ where: { bucket: BUCKET } });
}
