import { randomBytes } from 'node:crypto';
import { argon2Verify, argon2id } from 'hash-wasm';

/**
 * Single source of truth for password hashing.
 *
 * Uses the WebAssembly argon2 implementation rather than the native `argon2`
 * package. The production host (cPanel/EL8) restricts compiler access for
 * non-root users, and argon2's prebuilt binary is linked against GLIBC_2.34
 * while EL8 provides 2.28 — so neither compiling nor the prebuild works there.
 * WebAssembly runs anywhere Node runs, which removes the backend's only native
 * dependency and with it a whole class of deployment failure.
 *
 * The output is the standard PHC string (`$argon2id$v=19$m=…,t=…,p=…$salt$hash`)
 * with identical parameters, so hashes written by the native implementation
 * verify here and vice versa. No migration of stored passwords is required.
 */
const MEMORY_COST_KIB = 19_456;
const TIME_COST = 3;
const PARALLELISM = 1;
const HASH_LENGTH = 32;
const SALT_LENGTH = 16;

/** Minimum password length enforced across the API and the admin tooling. */
export const MIN_PASSWORD_LENGTH = 12;

export function hashPassword(plaintext: string): Promise<string> {
  return argon2id({
    password: plaintext,
    salt: randomBytes(SALT_LENGTH),
    memorySize: MEMORY_COST_KIB,
    iterations: TIME_COST,
    parallelism: PARALLELISM,
    hashLength: HASH_LENGTH,
    outputType: 'encoded',
  });
}

/**
 * Verify a plaintext password against a stored hash. Returns `false` instead of
 * throwing when the stored value is not a valid argon2 encoding (e.g. the
 * 'disabled' placeholder on the legacy sentinel account).
 */
export async function verifyPassword(storedHash: string, plaintext: string): Promise<boolean> {
  try {
    return await argon2Verify({ password: plaintext, hash: storedHash });
  } catch {
    return false;
  }
}
