// src/routes/usuarioMetricas.routes.js
const express = require('express');
const router = express.Router();

const pool = require('../config/db');
const handleValidation = require('../middleware/handleValidation');

const {
  idUsuarioParamValidator,
  createMetricasValidator,
  updateMetricasValidator,
  incrementMetricasValidator,
  listMetricasValidator,
} = require('../validators/usuarioMetricas.validators');

// Utilidad: recalcular nivel_actual y porcentaje_avance según tabla "niveles"
async function recalcularNivel(pool, id_usuario) {
  // Obtener puntos actuales
  const [[m]] = await pool.query(
    'SELECT puntos_totales FROM usuario_metricas WHERE id_usuario = ?',
    [id_usuario]
  );
  if (!m) return;

  const puntos = m.puntos_totales ?? 0;

  // Buscar nivel actual
  const [[nivelActual]] = await pool.query(
    `SELECT id_nivel, puntos_minimos, puntos_maximos
       FROM niveles
      WHERE puntos_minimos <= ? AND ? <= puntos_maximos
      ORDER BY puntos_minimos DESC
      LIMIT 1`,
    [puntos, puntos]
  );

  // Buscar siguiente nivel (para porcentaje de avance)
  const [[nivelSiguiente]] = await pool.query(
    `SELECT puntos_minimos, puntos_maximos
       FROM niveles
      WHERE puntos_minimos > ?
      ORDER BY puntos_minimos ASC
      LIMIT 1`,
    [nivelActual ? nivelActual.puntos_minimos : -1]
  );

  let porcentaje = 100.0;
  if (nivelActual && nivelSiguiente) {
    const base = nivelActual.puntos_minimos;
    const rango = Math.max(1, nivelSiguiente.puntos_minimos - base);
    porcentaje = ((puntos - base) * 100.0) / rango;
    if (porcentaje < 0) porcentaje = 0;
    if (porcentaje > 100) porcentaje = 100;
  }

  await pool.query(
    `UPDATE usuario_metricas
        SET nivel_actual = ?,
            porcentaje_avance = ?
      WHERE id_usuario = ?`,
    [nivelActual ? nivelActual.id_nivel : null, porcentaje, id_usuario]
  );
}

// ===================== Rutas ===================== //

// (Opcional) Listar paginado simple
router.get('/', listMetricasValidator, handleValidation, async (req, res) => {
  const { from_user_id = 0, limit = 100 } = req.query;
  try {
    const [rows] = await pool.query(
      `SELECT id_metricas, id_usuario, actividades_completadas, tiempo_total_minutos,
              puntos_totales, racha_dias, nivel_actual, porcentaje_avance, actualizado_en
         FROM usuario_metricas
        WHERE id_usuario > ?
        ORDER BY id_usuario ASC
        LIMIT ?`,
      [Number(from_user_id), Number(limit)]
    );
    res.json(rows);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'Error al listar métricas' });
  }
});

// Obtener métricas por usuario
router.get('/:id_usuario', idUsuarioParamValidator, handleValidation, async (req, res) => {
  try {
    const [rows] = await pool.query(
      `SELECT id_metricas, id_usuario, actividades_completadas, tiempo_total_minutos,
              puntos_totales, racha_dias, nivel_actual, porcentaje_avance, actualizado_en
         FROM usuario_metricas
        WHERE id_usuario = ?`,
      [req.params.id_usuario]
    );
    if (!rows.length) return res.status(404).json({ error: 'Métricas no encontradas' });
    res.json(rows[0]);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'Error al obtener métricas' });
  }
});

// Crear fila inicial (si no la haces al crear usuario)
router.post('/', createMetricasValidator, handleValidation, async (req, res) => {
  const { id_usuario, nivel_actual = null } = req.body;
  try {
    const [ins] = await pool.query(
      `INSERT INTO usuario_metricas (id_usuario, nivel_actual)
       VALUES (?, ?)
       ON DUPLICATE KEY UPDATE id_usuario = id_usuario`,
      [id_usuario, nivel_actual]
    );
    res.status(201).json({ message: 'Métricas creadas (o ya existían)', id_usuario });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'Error al crear métricas' });
  }
});

// Actualizar SET parcial (COALESCE)
router.put('/:id_usuario', updateMetricasValidator, handleValidation, async (req, res) => {
  const id_usuario = Number(req.params.id_usuario);
  const {
    actividades_completadas = null,
    tiempo_total_minutos = null,
    puntos_totales = null,
    racha_dias = null,
    nivel_actual = null,
    porcentaje_avance = null,
  } = req.body;

  try {
    const [r] = await pool.query(
      `UPDATE usuario_metricas
          SET actividades_completadas = COALESCE(?, actividades_completadas),
              tiempo_total_minutos   = COALESCE(?, tiempo_total_minutos),
              puntos_totales         = COALESCE(?, puntos_totales),
              racha_dias             = COALESCE(?, racha_dias),
              nivel_actual           = COALESCE(?, nivel_actual),
              porcentaje_avance      = COALESCE(?, porcentaje_avance)
        WHERE id_usuario = ?`,
      [
        actividades_completadas,
        tiempo_total_minutos,
        puntos_totales,
        racha_dias,
        nivel_actual,
        porcentaje_avance,
        id_usuario,
      ]
    );
    if (r.affectedRows === 0) return res.status(404).json({ error: 'Métricas no encontradas' });
    res.json({ message: 'Métricas actualizadas' });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'Error al actualizar métricas' });
  }
});

// Incrementar acumulados tras actividad
router.patch('/:id_usuario/increment', incrementMetricasValidator, handleValidation, async (req, res) => {
  const id_usuario = Number(req.params.id_usuario);
  const {
    actividades_add = 1,
    minutos_add = 0,
    puntos_add = 0,
    racha_dias_add = 0,
    reset_racha = false,
    recalcular_nivel = false,
  } = req.body;

  try {
    // crea si no existe (gracias a UNIQUE en id_usuario)
    await pool.query(
      `INSERT INTO usuario_metricas (id_usuario)
       VALUES (?)
       ON DUPLICATE KEY UPDATE id_usuario = id_usuario`,
      [id_usuario]
    );

    // suma deltas
    await pool.query(
      `UPDATE usuario_metricas
          SET actividades_completadas = actividades_completadas + ?,
              tiempo_total_minutos   = tiempo_total_minutos   + ?,
              puntos_totales         = puntos_totales         + ?,
              racha_dias             = CASE
                                          WHEN ? = 1 THEN 0
                                          ELSE racha_dias + ?
                                        END
        WHERE id_usuario = ?`,
      [
        Number(actividades_add || 0),
        Number(minutos_add || 0),
        Number(puntos_add || 0),
        reset_racha ? 1 : 0,
        Number(racha_dias_add || 0),
        id_usuario,
      ]
    );

    // Recalcular nivel/porcentaje si sumaste puntos o lo fuerzas
    if (Number(puntos_add) > 0 || recalcular_nivel) {
      await recalcularNivel(pool, id_usuario);
    }

    const [[out]] = await pool.query(
      `SELECT id_metricas, id_usuario, actividades_completadas, tiempo_total_minutos,
              puntos_totales, racha_dias, nivel_actual, porcentaje_avance, actualizado_en
         FROM usuario_metricas
        WHERE id_usuario = ?`,
      [id_usuario]
    );

    res.json({ message: 'Métricas incrementadas', metricas: out });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'Error al incrementar métricas' });
  }
});

module.exports = router;