const express = require('express');
const bcrypt = require('bcrypt');
const path = require('path');
const rateLimit = require('express-rate-limit');
const db = require('../lib/db');
const log = require('../lib/logger');

const router = express.Router();
const SALT_ROUNDS = 10;
// Dummy hash compared when the user doesn't exist, so login timing doesn't leak account existence.
const DUMMY_HASH = bcrypt.hashSync('wa-dev-tools-dummy-password', SALT_ROUNDS);

// Rate limiting for auth endpoints
const authLimiter = rateLimit({
  keyGenerator: (req) => (req.session && req.session.user && req.session.user.id) ? "user_" + req.session.user.id : req.ip,
  windowMs: 15 * 60 * 1000, // 15 min
  max: 10,                   // 10 attempts per window
  message: { error: 'Слишком много попыток. Попробуйте через 15 минут.' },
  standardHeaders: true,
  legacyHeaders: false,
});

// Pages
router.get('/login', (req, res) => {
  if (req.session.user) return res.redirect('/dashboard');
  res.sendFile(path.join(__dirname, '..', 'public', 'login.html'));
});

router.get('/register', (req, res) => {
  if (req.session.user) return res.redirect('/dashboard');
  res.sendFile(path.join(__dirname, '..', 'public', 'register.html'));
});

// Login API
router.post('/login', authLimiter, express.json(), express.urlencoded({ extended: true }), async (req, res) => {
  const { email, password } = req.body;

  if (!email || !password) {
    return res.status(400).json({ error: 'Email и пароль обязательны' });
  }

  try {
    const user = await db.findUserByEmail(email.toLowerCase().trim());
    // Always run bcrypt (dummy hash when user missing) so response time doesn't reveal account existence.
    const valid = await bcrypt.compare(password, (user && user.password_hash) ? user.password_hash : DUMMY_HASH);
    if (!user || !valid) {
      return res.status(401).json({ error: 'Неверный email или пароль' });
    }

    if (user.is_blocked) {
      return res.status(403).json({ error: 'Аккаунт заблокирован' });
    }

    await db.updateLastLogin(user.id);

    // Session regeneration (prevent session fixation)
    const returnTo = req.session.returnTo;
    req.session.regenerate((err) => {
      if (err) {
        log.error('Session regenerate error', { error: err.message });
        return res.status(500).json({ error: 'Ошибка сервера' });
      }

      req.session.user = {
        id: user.id,
        email: user.email,
        name: user.display_name || user.email.split('@')[0],
        role: user.role || 'user',
      };

      log.info(`Login: ${user.email}`);
      res.json({ ok: true, redirect: returnTo || '/dashboard' });
    });
  } catch (err) {
    log.error('Login error', { error: err.message });
    res.status(500).json({ error: 'Ошибка сервера' });
  }
});

// Sanitize display name (strip HTML tags)
function sanitizeName(name) {
  if (!name) return '';
  return name.replace(/<[^>]*>/g, '').trim().slice(0, 100);
}

// Register API
router.post('/register', authLimiter, express.json(), express.urlencoded({ extended: true }), async (req, res) => {
  const { email, password, password2 } = req.body;
  const name = sanitizeName(req.body.name);

  if (!email || !password) {
    return res.status(400).json({ error: 'Email и пароль обязательны' });
  }

  const emailClean = email.toLowerCase().trim();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailClean)) {
    return res.status(400).json({ error: 'Некорректный email' });
  }

  if (password.length < 6) {
    return res.status(400).json({ error: 'Пароль минимум 6 символов' });
  }

  if (password2 && password !== password2) {
    return res.status(400).json({ error: 'Пароли не совпадают' });
  }

  try {
    const existing = await db.findUserByEmail(emailClean);
    if (existing) {
      return res.status(409).json({ error: 'Этот email уже зарегистрирован' });
    }

    const hash = await bcrypt.hash(password, SALT_ROUNDS);
    const displayName = (name || '').trim() || emailClean.split('@')[0];
    const userId = await db.createUser(emailClean, hash, displayName);

    // Regenerate session before authenticating (prevent session fixation), same as login.
    req.session.regenerate((err) => {
      if (err) {
        log.error('Session regenerate error (register)', { error: err.message });
        return res.status(500).json({ error: 'Ошибка сервера' });
      }
      req.session.user = { id: userId, email: emailClean, name: displayName, role: 'user' };
      log.info(`Register: ${emailClean}`);
      res.json({ ok: true, redirect: '/dashboard' });
    });
  } catch (err) {
    log.error('Register error', { error: err.message });
    res.status(500).json({ error: 'Ошибка сервера' });
  }
});

// Logout
router.get('/logout', (req, res) => {
  req.session.destroy(() => {
    res.redirect('/');
  });
});

// Current user info
router.get('/me', (req, res) => {
  if (!req.session.user) return res.status(401).json({ error: 'Not authenticated' });
  res.json(req.session.user);
});

module.exports = router;
