require('dotenv').config();

const express = require('express');
const path = require('path');
const multer = require('multer');
const pool = require('./config/database');
const cookieParser = require('cookie-parser');

const app = express();
const PORT = process.env.PORT || 3000;

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const JWT_SECRET = process.env.JWT_SECRET;

app.use(express.json());
app.use(cookieParser());

// Proteger admin.html específicamente, ANTES de servir archivos estáticos
app.get('/admin.html', protegerAdminHTML, (req, res) => {
  res.sendFile(path.join(__dirname, '..', 'frontend', 'admin.html'));
});
app.use(express.static(path.join(__dirname, '..', 'frontend')));

// ============================================
// CONFIGURACIÓN DE SUBIDA DE IMÁGENES
// ============================================

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, path.join(__dirname, 'uploads', 'productos'));
  },
  filename: (req, file, cb) => {
    // Nombre único: timestamp + nombre original (evita que dos imágenes se sobrescriban)
    const nombreUnico = `${Date.now()}-${file.originalname}`;
    cb(null, nombreUnico);
  }
});

const upload = multer({ storage });

// Servir la carpeta uploads como archivos estáticos (para que el navegador pueda mostrarlas)
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

// ============================================
// MIDDLEWARE DE AUTENTICACIÓN
// ============================================
function verificarToken(req, res, next) {
  const token = req.cookies.token;

  if (!token) {
    return res.status(401).json({ error: 'No autorizado: falta el token' });
  }

  jwt.verify(token, JWT_SECRET, (err, decoded) => {
    if (err) {
      return res.status(403).json({ error: 'Token inválido o expirado' });
    }

    req.usuario = decoded;
    next();
  });
}

// Middleware específico para proteger el archivo admin.html
function protegerAdminHTML(req, res, next) {
  const token = req.cookies.token;

  if (!token) {
    return res.redirect('/login.html');
  }

  jwt.verify(token, JWT_SECRET, (err) => {
    if (err) {
      return res.redirect('/login.html');
    }
    next(); // token válido, dejar pasar la petición para que se sirva admin.html
  });
}

// ============================================
// ENDPOINTS DE PRODUCTOS
// ============================================

// GET: listar todos los productos (con nombre de categoría incluido)
app.get('/api/productos', async (req, res) => {
  try {
    const [productos] = await pool.query(`
      SELECT p.*, c.nombre AS categoriaNombre
      FROM productos p
      JOIN categorias c ON p.categoriaId = c.id
      ORDER BY p.id
    `);
    res.json(productos);
  } catch (error) {
    console.error('Error al obtener productos:', error);
    res.status(500).json({ error: 'Error al obtener productos' });
  }
});

// ENDPOINT PÚBLICO: solo datos seguros para la tienda (sin precioCompra)
app.get('/api/productos/publico', async (req, res) => {
try {
    const [productos] = await pool.query(`
    SELECT p.id, p.nombre, c.nombre AS categoria, p.precioVenta AS precio, 
            p.imagen, p.descripcion, p.stock, p.material
    FROM productos p
    JOIN categorias c ON p.categoriaId = c.id
    ORDER BY p.id
    `);

    // Convertir 'precio' de string a número antes de enviarlo al frontend
    const productosConvertidos = productos.map(p => ({
    ...p,
    precio: Number(p.precio)
    }));

    res.json(productosConvertidos);
} catch (error) {
    console.error('Error al obtener catálogo público:', error);
    res.status(500).json({ error: 'Error al obtener el catálogo' });
}
});

// POST: crear un nuevo producto (con imagen subida)
app.post('/api/productos', verificarToken, upload.single('imagen'), async (req, res) => {
  try {
    const { nombre, categoriaId, precioCompra, precioVenta, stock, descripcion } = req.body;
    let { material } = req.body;

    if (!req.file) {
      return res.status(400).json({ error: 'La imagen del producto es obligatoria' });
    }

    // Consultamos el nombre de la categoría para saber si el material aplica
    const [catRows] = await pool.query('SELECT nombre FROM categorias WHERE id = ?', [categoriaId]);
    const esReloj = catRows.length > 0 && catRows[0].nombre === 'Relojes';

    if (esReloj) {
      material = null; // los relojes no llevan material
    } else if (!material) {
      return res.status(400).json({ error: 'El material del producto es obligatorio' });
    }

    const rutaImagen = `/uploads/productos/${req.file.filename}`;

    const [resultado] = await pool.query(
      `INSERT INTO productos (nombre, categoriaId, precioCompra, precioVenta, stock, imagen, descripcion, material)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [nombre, categoriaId, precioCompra, precioVenta, stock, rutaImagen, descripcion, material]
    );

    res.status(201).json({
      id: resultado.insertId,
      nombre, categoriaId, precioCompra, precioVenta, stock, imagen: rutaImagen, descripcion, material
    });
  } catch (error) {
    console.error('Error al crear producto:', error);
    res.status(500).json({ error: 'Error al crear producto' });
  }
});

// PUT: actualizar un producto existente (con imagen opcional)
app.put('/api/productos/:id', verificarToken, upload.single('imagen'), async (req, res) => {
  try {
    const { id } = req.params;
    const { nombre, categoriaId, precioCompra, precioVenta, stock, descripcion, imagenActual } = req.body;
    let { material } = req.body;

    // Consultamos el nombre de la categoría para saber si el material aplica
    const [catRows] = await pool.query('SELECT nombre FROM categorias WHERE id = ?', [categoriaId]);
    const esReloj = catRows.length > 0 && catRows[0].nombre === 'Relojes';

    if (esReloj) {
      material = null;
    } else if (!material) {
      return res.status(400).json({ error: 'El material del producto es obligatorio' });
    }

    // Si subieron una imagen nueva, usamos esa ruta. Si no, conservamos la que ya tenía.
    const rutaImagen = req.file
      ? `/uploads/productos/${req.file.filename}`
      : imagenActual;

    const [resultado] = await pool.query(
      `UPDATE productos 
       SET nombre = ?, categoriaId = ?, precioCompra = ?, precioVenta = ?, stock = ?, imagen = ?, descripcion = ?, material = ?
       WHERE id = ?`,
      [nombre, categoriaId, precioCompra, precioVenta, stock, rutaImagen, descripcion, material, id]
    );

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

    res.json({ id: parseInt(id), nombre, categoriaId, precioCompra, precioVenta, stock, imagen: rutaImagen, descripcion, material });
  } catch (error) {
    console.error('Error al actualizar producto:', error);
    res.status(500).json({ error: 'Error al actualizar producto' });
  }
});

// DELETE: eliminar un producto
app.delete('/api/productos/:id', verificarToken, async (req, res) => {
  try {
    const { id } = req.params;
    const [resultado] = await pool.query('DELETE FROM productos WHERE id = ?', [id]);

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

    res.json({ mensaje: 'Producto eliminado correctamente' });
  } catch (error) {
    console.error('Error al eliminar producto:', error);
    res.status(500).json({ error: 'Error al eliminar producto' });
  }
});


// ============================================
// ENDPOINTS DE CATEGORÍAS
// ============================================

// GET: listar todas las categorías
app.get('/api/categorias', async (req, res) => {
  try {
    const [categorias] = await pool.query('SELECT * FROM categorias ORDER BY nombre');
    res.json(categorias);
  } catch (error) {
    console.error('Error al obtener categorías:', error);
    res.status(500).json({ error: 'Error al obtener categorías' });
  }
});

// POST: crear una nueva categoría
app.post('/api/categorias', verificarToken, async (req, res) => {
  try {
    const { nombre } = req.body;
    const [resultado] = await pool.query(
      'INSERT INTO categorias (nombre) VALUES (?)',
      [nombre]
    );
    res.status(201).json({ id: resultado.insertId, nombre });
  } catch (error) {
    if (error.code === 'ER_DUP_ENTRY') {
      return res.status(409).json({ error: 'Esa categoría ya existe' });
    }
    console.error('Error al crear categoría:', error);
    res.status(500).json({ error: 'Error al crear categoría' });
  }
});

// PUT: actualizar el nombre de una categoría existente
app.put('/api/categorias/:id', verificarToken, async (req, res) => {
  try {
    const { id } = req.params;
    const { nombre } = req.body;

    const [resultado] = await pool.query(
      'UPDATE categorias SET nombre = ? WHERE id = ?',
      [nombre, id]
    );

    if (resultado.affectedRows === 0) {
      return res.status(404).json({ error: 'Categoría no encontrada' });
    }

    res.json({ id: parseInt(id), nombre });
  } catch (error) {
    if (error.code === 'ER_DUP_ENTRY') {
      return res.status(409).json({ error: 'Ya existe una categoría con ese nombre' });
    }
    console.error('Error al actualizar categoría:', error);
    res.status(500).json({ error: 'Error al actualizar categoría' });
  }
});

// DELETE: eliminar una categoría
app.delete('/api/categorias/:id', verificarToken, async (req, res) => {
  try {
    const { id } = req.params;
    const [resultado] = await pool.query('DELETE FROM categorias WHERE id = ?', [id]);

    if (resultado.affectedRows === 0) {
      return res.status(404).json({ error: 'Categoría no encontrada' });
    }
    res.json({ mensaje: 'Categoría eliminada correctamente' });
  } catch (error) {
    if (error.code === 'ER_ROW_IS_REFERENCED_2') {
      return res.status(409).json({ error: 'No se puede eliminar: hay productos usando esta categoría' });
    }
    console.error('Error al eliminar categoría:', error);
    res.status(500).json({ error: 'Error al eliminar categoría' });
  }
});

// Verifica que la conexión a la base de datos esté activa
async function verificarConexionBD() {
  try {
    const [rows] = await pool.query('SELECT DATABASE() AS db');
    console.log(` 🗄️  Base de datos:  ${rows[0].db} (conectada ✅)`);
  } catch (error) {
    console.error(`   ❌ Error de conexión a la base de datos: ${error.message}`);
  }
}

// ============================================
// ENDPOINTS DE PEDIDOS
// ============================================

// POST: crear un nuevo pedido (público, sin autenticación - lo usan los clientes)
app.post('/api/pedidos', async (req, res) => {
  const connection = await pool.getConnection();
  try {
    const { nombreCliente, apellidoCliente, telefono, items } = req.body;

    if (!nombreCliente || !apellidoCliente || !telefono) {
      connection.release();
      return res.status(400).json({ error: 'Nombre, apellido y teléfono son obligatorios' });
    }

    if (!items || items.length === 0) {
      connection.release();
      return res.status(400).json({ error: 'El pedido debe tener al menos un producto' });
    }

    // Calculamos el total sumando cada producto x cantidad
    const total = items.reduce((acc, item) => acc + (item.precio * item.cantidad), 0);

    await connection.beginTransaction();

    // 1. Insertar el pedido principal
    const [resultadoPedido] = await connection.query(
      `INSERT INTO pedidos (nombreCliente, apellidoCliente, telefono, total)
       VALUES (?, ?, ?, ?)`,
      [nombreCliente, apellidoCliente, telefono, total]
    );

    const pedidoId = resultadoPedido.insertId;

    // 2. Insertar cada producto del carrito en pedido_detalle
    for (const item of items) {
      await connection.query(
        `INSERT INTO pedido_detalle (pedidoId, productoId, nombreProducto, cantidad, precioUnitario)
         VALUES (?, ?, ?, ?, ?)`,
        [pedidoId, item.id, item.nombre, item.cantidad, item.precio]
      );
    }

    await connection.commit();
    connection.release();

    res.status(201).json({ id: pedidoId, total, mensaje: 'Pedido registrado correctamente' });

  } catch (error) {
    await connection.rollback();
    connection.release();
    console.error('Error al crear pedido:', error);
    res.status(500).json({ error: 'Error al registrar el pedido' });
  }
});

// GET: listar todos los pedidos (protegido, solo para el admin)
app.get('/api/pedidos', verificarToken, async (req, res) => {
  try {
    const [pedidos] = await pool.query(
      'SELECT * FROM pedidos ORDER BY fechaCreacion DESC'
    );

    // Para cada pedido, traemos también sus productos (detalle)
    for (const pedido of pedidos) {
      const [detalle] = await pool.query(
        'SELECT * FROM pedido_detalle WHERE pedidoId = ?',
        [pedido.id]
      );
      pedido.productos = detalle;
    }

    res.json(pedidos);
  } catch (error) {
    console.error('Error al obtener pedidos:', error);
    res.status(500).json({ error: 'Error al obtener pedidos' });
  }
});

// PUT: actualizar el estado de un pedido (protegido)
app.put('/api/pedidos/:id/estado', verificarToken, async (req, res) => {
  try {
    const { id } = req.params;
    const { estado } = req.body;

    const [resultado] = await pool.query(
      'UPDATE pedidos SET estado = ? WHERE id = ?',
      [estado, id]
    );

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

    res.json({ mensaje: 'Estado actualizado correctamente' });
  } catch (error) {
    console.error('Error al actualizar estado del pedido:', error);
    res.status(500).json({ error: 'Error al actualizar estado' });
  }
});

// ============================================
// ENDPOINT DE RESUMEN DE VENTAS
// ============================================
app.get('/api/resumen-ventas', verificarToken, async (req, res) => {
  try {
    // 1. Total vendido este mes (solo pedidos Completados)
    const [totalMes] = await pool.query(`
      SELECT COALESCE(SUM(total), 0) AS totalVentas, COUNT(*) AS cantidadPedidos
      FROM pedidos
      WHERE estado = 'Completado'
        AND MONTH(fechaCreacion) = MONTH(CURDATE())
        AND YEAR(fechaCreacion) = YEAR(CURDATE())
    `);

    // 1.5 Ganancia del mes: (precio de venta - precio de compra) x cantidad, de pedidos Completados este mes
    const [gananciaMes] = await pool.query(`
      SELECT COALESCE(SUM((pd.precioUnitario - prod.precioCompra) * pd.cantidad), 0) AS ganancia
      FROM pedido_detalle pd
      JOIN pedidos p ON pd.pedidoId = p.id
      JOIN productos prod ON pd.productoId = prod.id
      WHERE p.estado = 'Completado'
        AND MONTH(p.fechaCreacion) = MONTH(CURDATE())
        AND YEAR(p.fechaCreacion) = YEAR(CURDATE())
    `);

    // 2. Pedidos por atender (Pendiente + Contactado, sin importar el mes)
    const [pendientes] = await pool.query(`
      SELECT COUNT(*) AS cantidad
      FROM pedidos
      WHERE estado IN ('Pendiente', 'Contactado')
    `);

    // 3. Top 5 productos más vendidos (de pedidos Completados, histórico)
    const [topProductos] = await pool.query(`
      SELECT pd.nombreProducto, SUM(pd.cantidad) AS totalVendido
      FROM pedido_detalle pd
      JOIN pedidos p ON pd.pedidoId = p.id
      WHERE p.estado = 'Completado'
      GROUP BY pd.nombreProducto
      ORDER BY totalVendido DESC
      LIMIT 5
    `);

    // 4. Ventas por categoría (de pedidos Completados, histórico)
    const [ventasPorCategoria] = await pool.query(`
      SELECT c.nombre AS categoria, SUM(pd.cantidad * pd.precioUnitario) AS totalVendido
      FROM pedido_detalle pd
      JOIN pedidos p ON pd.pedidoId = p.id
      JOIN productos prod ON pd.productoId = prod.id
      JOIN categorias c ON prod.categoriaId = c.id
      WHERE p.estado = 'Completado'
      GROUP BY c.nombre
      ORDER BY totalVendido DESC
    `);

    const totalVentas = Number(totalMes[0].totalVentas);
    const cantidadPedidos = totalMes[0].cantidadPedidos;
    const ganancia = Number(gananciaMes[0].ganancia);

    // 5. Productos con bajo stock (3 unidades o menos)
    const [bajoStock] = await pool.query(`
      SELECT COUNT(*) AS cantidad FROM productos WHERE stock <= 3
    `);

    // 6. Total de productos en catálogo
    const [totalCatalogo] = await pool.query(`
      SELECT COUNT(*) AS cantidad FROM productos
    `);

    res.json({
      totalVentasMes: totalVentas,
      cantidadPedidosMes: cantidadPedidos,
      gananciaMes: ganancia,
      pedidosPendientes: pendientes[0].cantidad,
      bajoStock: bajoStock[0].cantidad,
      totalCatalogo: totalCatalogo[0].cantidad,
      topProductos: topProductos,
      ventasPorCategoria: ventasPorCategoria.map(v => ({
        categoria: v.categoria,
        totalVendido: Number(v.totalVendido)
      }))
    });

  } catch (error) {
    console.error('Error al obtener resumen de ventas:', error);
    res.status(500).json({ error: 'Error al obtener resumen de ventas' });
  }
});

// ============================================
// ENDPOINT DE LOGIN
// ============================================
app.post('/api/login', async (req, res) => {
  try {
    const { usuario, password } = req.body;

    if (!usuario || !password) {
      return res.status(400).json({ error: 'Usuario y contraseña son obligatorios' });
    }

    // Buscar el usuario en la base de datos
    const [rows] = await pool.query('SELECT * FROM usuarios WHERE usuario = ?', [usuario]);

    if (rows.length === 0) {
      return res.status(401).json({ error: 'Usuario o contraseña incorrectos' });
    }

    const usuarioEncontrado = rows[0];

    // Comparar la contraseña escrita con el hash guardado
    const passwordValida = await bcrypt.compare(password, usuarioEncontrado.password);

    if (!passwordValida) {
      return res.status(401).json({ error: 'Usuario o contraseña incorrectos' });
    }

    // Generar el token JWT
    const token = jwt.sign(
    { id: usuarioEncontrado.id, usuario: usuarioEncontrado.usuario },
    JWT_SECRET,
    { expiresIn: '8h' }
    );

    // Guardar el token en una cookie httpOnly (JavaScript del navegador NO puede leerla)
    res.cookie('token', token, {
    httpOnly: true,
    maxAge: 8 * 60 * 60 * 1000, // 8 horas en milisegundos
    sameSite: 'strict'
    });

    res.json({
    nombre: usuarioEncontrado.nombre,
    usuario: usuarioEncontrado.usuario
    });

  } catch (error) {
    console.error('Error en login:', error);
    res.status(500).json({ error: 'Error al iniciar sesión' });
  }
});

// ============================================
// ENDPOINT DE LOGOUT
// ============================================
app.post('/api/logout', (req, res) => {
  res.clearCookie('token');
  res.json({ mensaje: 'Sesión cerrada correctamente' });
});

// Iniciando el Servidor
app.listen(PORT, async () => {
    console.log(`====================================================`);
    console.log(` ✨ Servidor de Relojería & Joyería KARINA activo ✨`);
    console.log(` 🌐 Tienda Pública: http://localhost:${PORT}`);
    console.log(` 🛠️  Panel Admin:    http://localhost:${PORT}/admin`);
    await verificarConexionBD();
    console.log(`====================================================`);
});