/**
 * ========================================
 * UTILIDADES DE AUTENTICACIÓN JWT
 * ========================================
 *
 * Este módulo maneja todo lo relacionado con JSON Web Tokens (JWT):
 * - Generación de tokens (login/register)
 * - Verificación de tokens (rutas protegidas)
 * - Middleware de autenticación
 *
 * FLUJO DE AUTENTICACIÓN:
 * 1. Usuario hace login/register → signToken() genera token
 * 2. Frontend guarda el token
 * 3. Frontend envía token en header: Authorization: Bearer <token>
 * 4. requireAuth() valida el token y extrae datos del usuario
 * 5. Si es válido, continúa a la ruta; si no, devuelve 401
 *
 * ORIGEN: Usado por auth.routes.js para login/register
 * DESTINO: Usado como middleware en todas las rutas protegidas
 */

const jwt = require('jsonwebtoken');

// ========================================
// CONFIGURACIÓN
// ========================================
// Secreto para firmar/verificar tokens (DEBE estar en .env en producción)
const JWT_SECRET = process.env.JWT_SECRET || 'dev-secret-change-me';

/**
 * ========================================
 * FUNCIÓN: signToken
 * ========================================
 * Genera un token JWT firmado
 *
 * @param {Object} payload - Datos a incluir en el token (ej: { id_usuario: 1, email: 'user@mail.com' })
 * @param {String} expiresIn - Tiempo de expiración (default: 8 horas)
 * @returns {String} Token JWT firmado
 *
 * ORIGEN: Se llama desde auth.routes.js después de login/register exitoso
 * DESTINO: El token se envía al frontend en la respuesta JSON
 *
 * EJEMPLO:
 *   const token = signToken({ id_usuario: 123, email: 'test@mail.com' });
 *   // Devuelve algo como: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
 */
function signToken(payload, expiresIn = '8h') {
  return jwt.sign(payload, JWT_SECRET, { expiresIn });
}

/**
 * ========================================
 * FUNCIÓN: verifyTokenPayload
 * ========================================
 * Verifica que un token sea válido y extrae su contenido
 *
 * @param {String} token - Token JWT a verificar
 * @returns {Object} Payload decodificado si es válido
 * @throws {Error} Si el token es inválido o expiró
 *
 * ORIGEN: Se llama desde requireAuth middleware
 * DESTINO: Retorna los datos del usuario para adjuntarlos a req.user
 */
function verifyTokenPayload(token) {
  return jwt.verify(token, JWT_SECRET);
}

/**
 * ========================================
 * MIDDLEWARE: requireAuth
 * ========================================
 * Middleware que protege rutas requiriendo autenticación válida
 *
 * FLUJO DE EJECUCIÓN:
 * 1. Extrae el header Authorization de la petición
 * 2. Valida que tenga formato: "Bearer <token>"
 * 3. Verifica que el token sea válido usando verifyTokenPayload()
 * 4. Extrae el id_usuario del payload
 * 5. Adjunta los datos del usuario a req.user
 * 6. Llama a next() para continuar a la ruta
 *
 * ORIGEN: Se importa en server.js y en rutas que necesitan protección
 * DESTINO: Si el token es válido, continúa a la ruta; si no, devuelve error 401
 *
 * USO EN RUTAS:
 *   router.get('/perfil', requireAuth, (req, res) => {
 *     console.log(req.user); // { id_usuario: 123, email: 'user@mail.com' }
 *     // ... lógica de la ruta
 *   });
 *
 * FORMATO ESPERADO DEL HEADER:
 *   Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
 *
 * @param {Request} req - Objeto de petición Express
 * @param {Response} res - Objeto de respuesta Express
 * @param {Function} next - Función para continuar al siguiente middleware
 */
function requireAuth(req, res, next) {
  try {
    // 1. Extrae el header Authorization
    const hdr = req.headers.authorization || '';
    const [scheme, token] = hdr.split(' ');

    // 2. Valida el formato "Bearer <token>"
    if (scheme !== 'Bearer' || !token || typeof token !== 'string') {
      return res.status(401).json({
        error: 'Token faltante o mal formado. Usa Authorization: Bearer <token>'
      });
    }

    // 3. Verifica el token y extrae el payload
    const decoded = verifyTokenPayload(token);

    // 4. Normaliza el campo id_usuario (por si viene con diferentes nombres)
    const id_usuario = decoded.id_usuario || decoded.id || decoded.user_id || decoded.userId;

    // 5. Valida que el token contenga un ID de usuario
    if (!id_usuario) {
      console.log('⚠️ Token sin id_usuario. Payload:', decoded);
      return res.status(401).json({ error: 'Token inválido (sin id de usuario)' });
    }

    // 6. Adjunta los datos del usuario a la petición
    // Ahora todas las rutas pueden acceder a req.user
    req.user = { ...decoded, id_usuario };

    // 7. Continúa al siguiente middleware o ruta
    return next();

  } catch (err) {
    // Manejo de errores de verificación de token
    console.log('⚠️ Token verification error:', err?.message || err);

    // Error específico: token expirado
    if (err.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'Token expirado' });
    }

    // Error específico: token malformado o firma inválida
    if (err.name === 'JsonWebTokenError') {
      return res.status(401).json({ error: 'Token inválido' });
    }

    // Cualquier otro error
    return res.status(500).json({ error: 'Error verificando token' });
  }
}

// ========================================
// EXPORTACIÓN
// ========================================
// Estas funciones se usan en:
// - signToken: auth.routes.js (login/register)
// - verifyTokenPayload: requireAuth middleware
// - requireAuth: server.js y todas las rutas protegidas
module.exports = { signToken, verifyTokenPayload, requireAuth };