import { Router } from 'express';
import {
  getUserByUsername, getUserById, createSession, getSession, deleteSession,
  listUsers, createUser, setUserEnabled, deleteUser, updateUserPassword,
} from '../../core/db.js';
import { verifyPassword, hashPassword, newSessionToken } from '../../lib/secure.js';
import { createRateLimiter } from '../../lib/rate-limit.js';

export const authRouter = Router();

const COOKIE = 'haikz_sid';

// Brute-force protection: max 5 gagal per IP / 15 menit, lalu lockout 15 menit
const loginLimiter = createRateLimiter({ windowMs: 15 * 60_000, max: 5, lockoutMs: 15 * 60_000 });

// ---- helpers ----
function setSessionCookie(res, token, expiresUnix) {
  res.cookie(COOKIE, token, {
    httpOnly: true,
    sameSite: 'lax',
    secure: true, // HTTPS only — akses lewat nginx TLS (haikzs.tech). Nutup pencurian cookie via plaintext.
    expires: new Date(expiresUnix * 1000),
    path: '/',
  });
}

// Middleware: resolve current user from session cookie. Attaches req.user (or null).
export function authMiddleware(req, res, next) {
  const token = req.cookies?.[COOKIE];
  const session = getSession(token);
  if (session) {
    const user = getUserById(session.user_id);
    if (user && user.enabled) {
      req.user = { id: user.id, username: user.username, role: user.role };
      req.sessionToken = token;
    }
  }
  next();
}

// Guard: require logged-in user
export function requireAuth(req, res, next) {
  if (!req.user) return res.status(401).json({ error: 'not authenticated' });
  next();
}

// Guard: require admin
export function requireAdmin(req, res, next) {
  if (!req.user) return res.status(401).json({ error: 'not authenticated' });
  if (req.user.role !== 'admin') return res.status(403).json({ error: 'admin only' });
  next();
}

// ---- routes ----
authRouter.post('/login', (req, res) => {
  const { username, password } = req.body || {};
  if (!username || !password) return res.status(400).json({ error: 'username & password required' });

  // Brute-force protection per IP
  const ip = req.ip || req.headers['x-forwarded-for'] || req.socket?.remoteAddress || 'unknown';
  const rl = loginLimiter.check(ip);
  if (!rl.allowed) {
    res.set('Retry-After', String(rl.retryAfter));
    return res.status(429).json({ error: `Terlalu banyak percobaan. Coba lagi dalam ${Math.ceil(rl.retryAfter / 60)} menit.` });
  }

  const user = getUserByUsername(username);
  if (!user || !user.enabled || !verifyPassword(password, user.password_hash)) {
    return res.status(401).json({ error: 'username atau password salah' });
  }

  // Login sukses -> reset counter IP ini
  loginLimiter.reset(ip);

  const token = newSessionToken();
  const expires = createSession(token, user.id);
  setSessionCookie(res, token, expires);
  res.json({ ok: true, user: { id: user.id, username: user.username, role: user.role } });
});

authRouter.post('/logout', (req, res) => {
  if (req.sessionToken) deleteSession(req.sessionToken);
  res.clearCookie(COOKIE, { path: '/' });
  res.json({ ok: true });
});

authRouter.get('/me', (req, res) => {
  if (!req.user) return res.status(401).json({ error: 'not authenticated' });
  res.json({ user: req.user });
});

// Change own password
authRouter.post('/change-password', requireAuth, (req, res) => {
  const { old_password, new_password } = req.body || {};
  if (!old_password || !new_password) return res.status(400).json({ error: 'old & new password required' });
  if (String(new_password).length < 6) return res.status(400).json({ error: 'password min 6 char' });

  const user = getUserById(req.user.id);
  if (!verifyPassword(old_password, user.password_hash)) {
    return res.status(401).json({ error: 'password lama salah' });
  }
  updateUserPassword(user.id, hashPassword(new_password));
  res.json({ ok: true });
});

// ---- admin: user management ----
authRouter.get('/users', requireAdmin, (req, res) => {
  res.json(listUsers());
});

authRouter.post('/users', requireAdmin, (req, res) => {
  const { username, password, role } = req.body || {};
  if (!username || !password) return res.status(400).json({ error: 'username & password required' });
  if (String(password).length < 6) return res.status(400).json({ error: 'password min 6 char' });
  if (getUserByUsername(username)) return res.status(400).json({ error: 'username sudah dipakai' });

  const id = createUser({
    username,
    passwordHash: hashPassword(password),
    role: role === 'admin' ? 'admin' : 'user',
  });
  res.json({ ok: true, id });
});

authRouter.post('/users/:id/enabled', requireAdmin, (req, res) => {
  setUserEnabled(parseInt(req.params.id), !!req.body.enabled);
  res.json({ ok: true });
});

authRouter.post('/users/:id/password', requireAdmin, (req, res) => {
  const { new_password } = req.body || {};
  if (!new_password || String(new_password).length < 6) return res.status(400).json({ error: 'password min 6 char' });
  updateUserPassword(parseInt(req.params.id), hashPassword(new_password));
  res.json({ ok: true });
});

authRouter.delete('/users/:id', requireAdmin, (req, res) => {
  const id = parseInt(req.params.id);
  if (id === req.user.id) return res.status(400).json({ error: 'gak bisa hapus diri sendiri' });
  deleteUser(id);
  res.json({ ok: true });
});
