/**
 * ========================================
 * RUTAS DE AUTENTICACIÓN
 * ========================================
 *
 * Este módulo maneja todas las operaciones relacionadas con autenticación
 * y gestión de perfil de usuarios:
 * - Registro de nuevos usuarios
 * - Login (inicio de sesión)
 * - Obtener perfil del usuario autenticado
 * - Actualizar perfil
 * - Cambiar contraseña
 *
 * ORIGEN: Se registra en server.js como app.use('/api/auth', authRoutes)
 * DESTINO: Todas las rutas aquí comienzan con /api/auth/*
 *
 * TABLA DE RUTAS:
 * POST   /api/auth/register       - Crear nuevo usuario
 * POST   /api/auth/login          - Iniciar sesión
 * GET    /api/auth/me             - Obtener perfil (requiere auth)
 * PUT    /api/auth/me/profile     - Actualizar perfil (requiere auth)
 * PUT    /api/auth/me/password    - Cambiar contraseña (requiere auth)
 */

const express = require('express');
const bcrypt = require('bcryptjs');                          // Para hashear/verificar contraseñas
const pool = require('../config/db');                        // Pool de conexiones a MySQL
const { signToken, requireAuth } = require('../utils/jwt');  // JWT: generar y verificar tokens
const { registerValidator, loginValidator } = require('../validators/auth.validators');
const handleValidation = require('../middleware/handleValidation');

const router = express.Router();

/**
 * ========================================
 * POST /api/auth/register
 * ========================================
 * Registra un nuevo usuario en el sistema
 *
 * FLUJO DE EJECUCIÓN:
 * 1. registerValidator valida los datos del body
 * 2. handleValidation verifica que no haya errores de validación
 * 3. Verifica que el email no esté registrado
 * 4. Hashea la contraseña con bcrypt
 * 5. Inserta el usuario en la base de datos
 * 6. Genera un token JWT
 * 7. Devuelve el token y los datos del usuario
 *
 * REQUEST BODY:
 *   {
 *     "nombre": "Juan",
 *     "apellido": "Pérez",
 *     "email": "juan@mail.com",
 *     "genero": "M",
 *     "password": "miPassword123"
 *   }
 *
 * RESPONSE (201):
 *   {
 *     "msg": "Usuario registrado con éxito",
 *     "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
 *     "user": {
 *       "id_usuario": 1,
 *       "nombre": "Juan",
 *       "apellido": "Pérez",
 *       "email": "juan@mail.com",
 *       "genero": "M"
 *     }
 *   }
 *
 * DESTINO: Frontend guarda el token y lo usa en peticiones futuras
 */
router.post('/register', registerValidator, handleValidation, async (req, res) => {
  const { nombre, apellido, email, genero, password } = req.body;

  try {
    // 1. Verifica si el email ya está registrado
    const [exists] = await pool.query(
      'SELECT id_usuario FROM usuarios WHERE email = ?',
      [email]
    );

    if (exists.length) {
      // Email duplicado - retorna error 409 Conflict
      return res.status(409).json({ error: 'Email ya registrado' });
    }

    // 2. Hashea la contraseña (bcrypt con 10 rondas de salt)
    // NUNCA guardar contraseñas en texto plano
    const hash = await bcrypt.hash(password, 10);

    // 3. Inserta el nuevo usuario en la base de datos
    const [result] = await pool.query(
      `INSERT INTO usuarios (nombre, apellido, email, genero, password_hash, fecha_registro, activo)
       VALUES (?, ?, ?, ?, ?, NOW(), 1)`,
      [nombre, apellido, email, genero, hash]
    );

    // 4. Genera el token JWT con el ID del usuario recién creado
    const token = signToken({ id_usuario: result.insertId, email });

    // 5. Prepara el objeto de usuario (sin el password_hash)
    const user = {
      id_usuario: result.insertId,
      nombre,
      apellido,
      email,
      genero
    };

    // 6. Devuelve respuesta exitosa con el token y datos del usuario
    return res.status(201).json({
      msg: 'Usuario registrado con éxito',
      token,
      user
    });

  } catch (err) {
    console.error('REGISTER ERROR:', err);
    return res.status(500).json({ error: 'Error en el servidor' });
  }
});

/**
 * ========================================
 * POST /api/auth/login
 * ========================================
 * Autentica a un usuario existente
 *
 * FLUJO DE EJECUCIÓN:
 * 1. loginValidator valida email y password
 * 2. handleValidation verifica errores
 * 3. Busca el usuario por email en la BD
 * 4. Verifica que el usuario esté activo
 * 5. Compara la contraseña con bcrypt.compare()
 * 6. Genera token JWT
 * 7. Devuelve token y datos del usuario
 *
 * REQUEST BODY:
 *   {
 *     "email": "juan@mail.com",
 *     "password": "miPassword123"
 *   }
 *
 * RESPONSE (200):
 *   {
 *     "msg": "Login exitoso",
 *     "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
 *     "user": { "id_usuario": 1, "nombre": "Juan", ... }
 *   }
 *
 * ERRORES:
 * - 401: Email no existe o contraseña incorrecta
 * - 401: Usuario inactivo
 */
router.post('/login', loginValidator, handleValidation, async (req, res) => {
  const { email, password } = req.body;

  try {
    // 1. Busca el usuario por email (incluye password_hash para comparar)
    const [users] = await pool.query(
      `SELECT id_usuario, nombre, apellido, email, genero, password_hash, activo
         FROM usuarios
        WHERE email = ?`,
      [email]
    );

    // 2. Verifica que el usuario exista
    if (!users.length) {
      // Mensaje genérico para no revelar si el email existe
      return res.status(401).json({ error: 'Credenciales inválidas' });
    }

    const u = users[0];

    // 3. Verifica que el usuario esté activo
    if (Number(u.activo) === 0) {
      return res.status(401).json({ error: 'Usuario inactivo' });
    }

    // 4. Compara la contraseña ingresada con el hash almacenado
    const ok = await bcrypt.compare(password, u.password_hash || '');
    if (!ok) {
      return res.status(401).json({ error: 'Credenciales inválidas' });
    }

    // 5. Genera token JWT con los datos del usuario
    const token = signToken({ id_usuario: u.id_usuario, email: u.email });

    // 6. Prepara el objeto de usuario (sin password_hash por seguridad)
    const user = {
      id_usuario: u.id_usuario,
      nombre: u.nombre,
      apellido: u.apellido,
      email: u.email,
      genero: u.genero
    };

    // 7. Devuelve respuesta exitosa
    return res.json({ msg: 'Login exitoso', token, user });

  } catch (err) {
    console.error('LOGIN ERROR:', err);
    return res.status(500).json({ error: 'Error en el servidor' });
  }
});

/**
 * ========================================
 * PUT /api/auth/me/profile
 * ========================================
 * Actualiza nombre y/o apellido del usuario autenticado
 *
 * REQUIERE: Token JWT en header Authorization
 * FLUJO: requireAuth valida token → actualiza en BD → devuelve usuario actualizado
 */
router.put('/me/profile', requireAuth, async (req, res) => {
  try {
    const { id_usuario } = req.user;
    const { nombre = null, apellido = null } = req.body;

    if (nombre === null && apellido === null) {
      return res.status(400).json({ error: 'Sin cambios' });
    }

    const [result] = await pool.query(
      `UPDATE usuarios
          SET nombre   = COALESCE(?, nombre),
              apellido = COALESCE(?, apellido)
        WHERE id_usuario = ?`,
      [nombre, apellido, id_usuario]
    );

    if (result.affectedRows === 0) {
      return res.status(404).json({ error: 'Usuario no encontrado' });
    }

    const [rows] = await pool.query(
      `SELECT id_usuario, nombre, apellido, email, genero
         FROM usuarios
        WHERE id_usuario = ?`,
      [id_usuario]
    );

    return res.json({ ok: true, user: rows[0] });
  } catch (e) {
    console.error('PUT /me/profile', e);
    return res.status(500).json({ error: 'Error al actualizar perfil' });
  }
});

/**
 * ========================================
 * GET /api/auth/me
 * ========================================
 * Devuelve el perfil completo del usuario autenticado + sus roles
 *
 * REQUIERE: Token JWT
 * FLUJO: requireAuth → consulta usuario → consulta roles → devuelve ambos
 */
router.get('/me', requireAuth, async (req, res) => {
  try {
    const { id_usuario } = req.user;

    // Usuario básico
    const [urows] = await pool.query(
      `SELECT id_usuario, nombre, apellido, email, genero
         FROM usuarios
        WHERE id_usuario = ?`,
      [id_usuario]
    );
    if (!urows.length) {
      return res.status(404).json({ error: 'Usuario no encontrado' });
    }

    // Roles
    const [rrows] = await pool.query(
      `SELECT r.id_rol, r.nombre
         FROM usuarios_roles ur
         JOIN roles r ON r.id_rol = ur.id_rol
        WHERE ur.id_usuario = ?`,
      [id_usuario]
    );

    const user = { ...urows[0], roles: rrows || [] };
    return res.json({ ok: true, user });
  } catch (e) {
    console.error('GET /api/auth/me', e);
    return res.status(500).json({ error: 'Error al obtener perfil' });
  }
});

/**
 * ========================================
 * PUT /api/auth/me/password
 * ========================================
 * Cambia la contraseña del usuario autenticado
 *
 * REQUIERE: Token JWT + contraseña actual correcta
 * FLUJO: requireAuth → verifica contraseña actual → hashea nueva → actualiza BD
 */
router.put('/me/password', requireAuth, async (req, res) => {
  try {
    const { id_usuario } = req.user;
    const { actual, nueva } = req.body;

    if (!actual || !nueva) {
      return res.status(400).json({ error: 'Faltan campos' });
    }

    // Obtiene hash actual
    const [rows] = await pool.query(
      'SELECT password_hash FROM usuarios WHERE id_usuario = ?',
      [id_usuario]
    );
    if (!rows.length) {
      return res.status(404).json({ error: 'Usuario no encontrado' });
    }

    const match = await bcrypt.compare(actual, rows[0].password_hash);
    if (!match) {
      return res.status(400).json({ error: 'La contraseña actual no coincide' });
    }

    const newHash = await bcrypt.hash(nueva, 10);
    await pool.query(
      'UPDATE usuarios SET password_hash = ? WHERE id_usuario = ?',
      [newHash, id_usuario]
    );

    return res.json({ ok: true, message: 'Contraseña actualizada' });
  } catch (e) {
    console.error('PUT /me/password', e);
    return res.status(500).json({ error: 'Error al actualizar contraseña' });
  }
});

module.exports = router;