const express = require('express');
const router = express.Router();
const { generateToken, verifyToken, verifyPassword, getCredentials } = require('../utils/auth.js');

const COOKIE_NAME = 'libreportal_token';
const COOKIE_OPTS = {
  httpOnly: true,
  sameSite: 'strict',
  maxAge: 30 * 24 * 60 * 60 * 1000
};

// Per-IP login rate limit: 10 attempts per 15 minutes. Lockout doubles each subsequent
// trip so a sustained attacker hits exponentially long waits.
const LOGIN_WINDOW_MS = 15 * 60 * 1000;
const LOGIN_MAX_ATTEMPTS = 10;
const loginAttempts = new Map(); // ip -> { count, firstAttempt, lockedUntil }

function checkLoginRate(ip) {
  const now = Date.now();
  const entry = loginAttempts.get(ip);
  if (!entry) return { allowed: true };
  if (entry.lockedUntil && now < entry.lockedUntil) {
    return { allowed: false, retryAfter: Math.ceil((entry.lockedUntil - now) / 1000) };
  }
  if (now - entry.firstAttempt > LOGIN_WINDOW_MS) {
    loginAttempts.delete(ip);
  }
  return { allowed: true };
}

function recordFailedLogin(ip) {
  const now = Date.now();
  const entry = loginAttempts.get(ip) || { count: 0, firstAttempt: now, lockedUntil: 0 };
  entry.count += 1;
  if (entry.count >= LOGIN_MAX_ATTEMPTS) {
    const prevLockMs = entry.lockedUntil ? entry.lockedUntil - entry.firstAttempt : 0;
    const lockMs = Math.max(LOGIN_WINDOW_MS, prevLockMs * 2);
    entry.lockedUntil = now + lockMs;
  }
  loginAttempts.set(ip, entry);
}

function clearLoginAttempts(ip) {
  loginAttempts.delete(ip);
}

router.post('/login', async (req, res) => {
  const ip = req.ip || req.socket?.remoteAddress || 'unknown';
  const rate = checkLoginRate(ip);
  if (!rate.allowed) {
    res.setHeader('Retry-After', rate.retryAfter);
    return res.status(429).json({ error: 'Too many login attempts. Try again later.' });
  }

  const { username, password } = req.body || {};
  if (!username || !password) {
    return res.status(400).json({ error: 'Username and password required' });
  }
  try {
    const creds = getCredentials();
    const usernameMatch = username === creds.username;
    const passwordMatch = await verifyPassword(password, creds.passwordHash);
    if (!usernameMatch || !passwordMatch) {
      recordFailedLogin(ip);
      // Constant-time delay to prevent timing attacks
      await new Promise(r => setTimeout(r, 500));
      return res.status(401).json({ error: 'Invalid credentials' });
    }
    clearLoginAttempts(ip);
    const token = generateToken(username);
    res.cookie(COOKIE_NAME, token, COOKIE_OPTS);
    res.json({ success: true, username });
  } catch (error) {
    console.error('[Auth] Login error:', error.message);
    res.status(500).json({ error: 'Internal error' });
  }
});

router.post('/logout', (req, res) => {
  res.clearCookie(COOKIE_NAME);
  res.json({ success: true });
});

router.get('/status', (req, res) => {
  const token = req.cookies?.[COOKIE_NAME];
  if (!token) return res.json({ authenticated: false });
  const payload = verifyToken(token);
  if (!payload) return res.json({ authenticated: false });
  res.json({ authenticated: true, username: payload.sub });
});

module.exports = router;
