import { User } from "@/db/models";
import { AppError } from "@/lib/errors";
import { isMysqlActive } from "@/db/activeDatabase";

const MAX_FAILED = 6;
const LOCK_MS = 15 * 60 * 1000;

type LockState = { fails: number; lockedUntil?: number };
const byEmail = new Map<string, LockState>();

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

export function assertNotLocked(email: string) {
  const state = byEmail.get(key(email));
  if (!state?.lockedUntil) return;
  if (Date.now() < state.lockedUntil) {
    const mins = Math.ceil((state.lockedUntil - Date.now()) / 60000);
    throw new AppError(429, `Account temporarily locked. Try again in ${mins} minute(s).`);
  }
  // lock expired
  byEmail.delete(key(email));
}

export function recordLoginFailure(email: string) {
  const k = key(email);
  const prev = byEmail.get(k) || { fails: 0 };
  const fails = prev.fails + 1;
  if (fails >= MAX_FAILED) {
    byEmail.set(k, { fails, lockedUntil: Date.now() + LOCK_MS });
    return { locked: true, fails };
  }
  byEmail.set(k, { fails });
  return { locked: false, fails };
}

export function clearLoginFailures(email: string) {
  byEmail.delete(key(email));
}

/** Optional: persist lock note on user for observability (non-blocking). */
export async function touchUserLoginMeta(email: string, ok: boolean) {
  // MySQL-primary cutover: never touch mongoose (not connected).
  if (isMysqlActive()) {
    return;
  }
  try {
    if (ok) {
      await User.updateOne(
        { email: key(email) },
        { $unset: { loginLockedUntil: 1 }, $set: { failedLoginCount: 0 } },
      );
    }
  } catch {
    /* schema fields may not exist — ignore */
  }
}
