import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

export const ADMIN_COOKIE_NAME = "admin_session";
const SESSION_TTL_S = 12 * 3600; // 12h
const LOCKOUT_WINDOW_MIN = 15;
const LOCKOUT_MAX_ATTEMPTS = 5;
// Hash bcrypt valide mais sans correspondance, utilisé pour égaliser le temps
// de réponse quand le username n'existe pas (évite l'énumération de comptes).
const DUMMY_HASH = "$2b$12$CwTycUXWue0Thq9StjUM0uJ8vKR1dlT0LYzGsv8ZE8nFI8q9Z5T9.";

function jwtSecret() {
  const secret = (process.env.ADMIN_JWT_SECRET || "").trim();
  if (!secret || secret.length < 32) {
    throw new Error("ADMIN_JWT_SECRET manquant ou trop court (min 32 caractères)");
  }
  return secret;
}

export async function seedAdminUser(pool) {
  const username = (process.env.ADMIN_SEED_USERNAME || "").trim();
  const passwordHash = (process.env.ADMIN_SEED_PASSWORD_HASH || "").trim();
  if (!username || !passwordHash) return;

  await pool.query(
    `INSERT INTO admin_users (username, password_hash)
     VALUES ($1, $2)
     ON CONFLICT (username) DO NOTHING`,
    [username, passwordHash]
  );
}

export function signAdminSession(username) {
  return jwt.sign({ sub: username }, jwtSecret(), { expiresIn: SESSION_TTL_S });
}

export function verifyAdminSession(token) {
  try {
    const payload = jwt.verify(token, jwtSecret());
    return typeof payload.sub === "string" ? payload.sub : null;
  } catch {
    return null;
  }
}

export async function isLockedOut(pool, username, ip) {
  const r = await pool.query(
    `SELECT count(*)::int AS n
     FROM admin_login_attempts
     WHERE success = false
       AND created_at > now() - make_interval(mins => $1)
       AND (username = $2 OR ip = $3)`,
    [LOCKOUT_WINDOW_MIN, username, ip]
  );
  return r.rows[0].n >= LOCKOUT_MAX_ATTEMPTS;
}

export async function recordLoginAttempt(pool, username, ip, success) {
  await pool.query(
    `INSERT INTO admin_login_attempts (username, ip, success) VALUES ($1, $2, $3)`,
    [username, ip, success]
  );
}

export async function verifyPassword(pool, username, password) {
  const r = await pool.query(
    `SELECT password_hash FROM admin_users WHERE username = $1`,
    [username]
  );
  const hash = r.rows.length ? r.rows[0].password_hash : DUMMY_HASH;
  const valid = await bcrypt.compare(password, hash);
  return valid && r.rows.length > 0;
}

export async function markLoginSuccess(pool, username) {
  await pool.query(
    `UPDATE admin_users SET last_login_at = now() WHERE username = $1`,
    [username]
  );
}

export function requireAdminSession(req, reply) {
  const token = req.cookies?.[ADMIN_COOKIE_NAME];
  const username = token ? verifyAdminSession(token) : null;
  if (!username) {
    reply.code(401).send({ ok: false, error: "unauthorized" });
    return null;
  }
  return username;
}

export async function writeAuditLog(pool, adminUsername, action, targetTable, targetId, before, after) {
  await pool.query(
    `INSERT INTO admin_audit_log (admin_username, action, target_table, target_id, before_data, after_data)
     VALUES ($1, $2, $3, $4, $5, $6)`,
    [adminUsername, action, targetTable, String(targetId), before ? JSON.stringify(before) : null, after ? JSON.stringify(after) : null]
  );
}
