
async function sql_inyec(req, res, dbcentral) {
    try {
        const store_id = req.query.store_id;
        const id_cliente = req.query.id_cliente;

        if (!store_id) {
            return res.status(400).json({ error: "store_id es requerido" });
        }

        // Validar que store_id sea un número para evitar errores de tipo en la DB
        if (isNaN(store_id)) {
            return res.status(400).json({
                error: "store_id inválido",
                message: "El store_id debe ser un valor numérico"
            });
        }

        // Registrar/Actualizar Heartbeat cada vez que una tienda consulta
        await dbcentral.query(
            `INSERT INTO tb_store_process_heartbeat 
            (store_id, process_name, instance_id, status, extra_info, id_cliente) 
            VALUES (?, ?, ?, ?, ?, ?) 
            ON DUPLICATE KEY UPDATE 
            status = 'alive', 
            last_ping = CURRENT_TIMESTAMP;`,
            {
                replacements: [
                    store_id,
                    'sql_inyector',
                    'sql_inyector',
                    'alive',
                    JSON.stringify({ message: 'Consultando comandos', timestamp: new Date() }),
                    id_cliente || null
                ]
            }
        );

        // Consultar comandos pendientes para este store_id
        const [results] = await dbcentral.query(
            "SELECT * FROM tb_sql_inyector WHERE store_id = ? and id_cliente=? AND estado = '0' LIMIT 1",
            {
                replacements: [store_id, id_cliente]
            }
        );

        if (results.length === 0) {
            return res.status(204).json({
                message: "No hay comandos pendientes"
            });
        }

        const command = results[0];

        // Construir la respuesta solicitada
        const response = {
            command_id: command.command_id,
            sql: command.sql,
            privilegio: command.privilegio || "READ" // Valor por defecto si no existe la columna
        };

        // Respuesta
        res.status(200).json(response);

    } catch (error) {
        console.error("❌ Error al procesar consulta sql_inyec:", error.message);
        res.status(500).json({
            error: "Error interno del servidor",
            message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
        });
    }
}

async function save_result_inyec(req, res, dbcentral) {
    try {
        let { command_id, result } = req.body;

        if (!command_id) {
            return res.status(400).json({ error: "command_id es requerido" });
        }

        // Si no se envía una propiedad 'result' explícita, asumimos que todo el body es la respuesta
        if (result === undefined) {
            result = req.body;
        }

        // Serializar el resultado a JSON si es un objeto
        const jsonResponse = typeof result === 'object' ? JSON.stringify(result) : result;

        const [updateResult] = await dbcentral.query(
            `UPDATE tb_sql_inyector SET json_response = ?, estado = '1' WHERE command_id = ?`,
            {
                replacements: [jsonResponse, command_id]
            }
        );

        // En algunas configuraciones de Sequelize/MySQL, el resultado de un update puede variar.
        // Verificamos si hubo cambios (affectedRows) si está disponible en updateResult.
        // Nota: updateResult suele ser un objeto con info del resultado en raw query.

        res.status(200).json({
            success: true,
            message: "Resultado guardado correctamente"
        });

    } catch (error) {
        console.error("❌ Error al guardar resultado:", error.message);
        res.status(500).json({
            error: "Error interno del servidor",
            message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
        });
    }
}

async function create_command(req, res, dbcentral) {
    try {
        const { store_id, sql, privilegio, id_user, id_cliente } = req.body;

        if (!store_id || !sql) {
            return res.status(400).json({ error: "store_id y sql son requeridos" });
        }

        if (isNaN(store_id)) {
            return res.status(400).json({
                error: "store_id inválido",
                message: "El store_id debe ser un valor numérico"
            });
        }

        const [commandId] = await dbcentral.query(
            "INSERT INTO tb_sql_inyector (store_id, `sql`, privilegio, id_user, id_cliente, estado) VALUES (?, ?, ?, ?, ?, '0')",
            {
                replacements: [store_id, sql, privilegio || 'READ', id_user || null, id_cliente || null]
            }
        );

        res.status(201).json({
            success: true,
            message: "Comando creado exitosamente",
            command_id: commandId
        });

    } catch (error) {
        console.error("❌ Error al crear comando:", error.message);
        res.status(500).json({
            error: "Error interno del servidor",
            message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
        });
    }
}

async function get_command_status(req, res, dbcentral) {
    try {
        const command_id = req.params.command_id;

        if (!command_id) {
            return res.status(400).json({ error: "command_id es requerido" });
        }

        const [results] = await dbcentral.query(
            `SELECT * FROM tb_sql_inyector WHERE command_id = ? AND estado = '1'`,
            {
                replacements: [command_id]
            }
        );

        if (results.length === 0) {
            // Verificamos si existe pero está en otro estado para dar un mensaje más claro, 
            // o simplemente retornamos 404 si no se encuentra completado.
            // Para ser simple y directo como en los otros endpoints:
            return res.status(404).json({
                message: "Comando no encontrado o aún no completado"
            });
        }

        const command = results[0];
        // Intentar parsear el json_response si es un string
        let jsonResponse = command.json_response;
        try {
            if (typeof jsonResponse === 'string') {
                jsonResponse = JSON.parse(jsonResponse);
            }
        } catch (e) {
            // Si falla el parseo, dejamos el string original
        }

        res.status(200).json({
            command_id: command.command_id,
            status: "completed",
            result: jsonResponse,
            processed_at: command.fecha_proceso
        });

    } catch (error) {
        console.error("❌ Error al obtener estado del comando:", error.message);
        res.status(500).json({
            error: "Error interno del servidor",
            message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
        });
    }
}

async function get_commands_by_user(req, res, dbcentral) {
    try {
        const id_user = req.params.id_user;
        const limit = req.query.limit || 50;

        if (!id_user) {
            return res.status(400).json({ error: "id_user es requerido" });
        }

        const [results] = await dbcentral.query(
            `SELECT command_id, store_id, \`sql\`, privilegio, estado, fecha_solicitud, fecha_proceso, json_response 
             FROM tb_sql_inyector 
             WHERE id_user = ? 
             ORDER BY command_id DESC 
             LIMIT ?`,
            {
                replacements: [id_user, parseInt(limit)]
            }
        );

        // Parsear cada json_response si es necesario
        const formattedResults = results.map(cmd => {
            let jsonResponse = cmd.json_response;
            try {
                if (typeof jsonResponse === 'string') {
                    jsonResponse = JSON.parse(jsonResponse);
                }
            } catch (e) { }

            return {
                ...cmd,
                json_response: jsonResponse
            };
        });

        res.status(200).json(formattedResults);

    } catch (error) {
        console.error("❌ Error al obtener comandos por usuario:", error.message);
        res.status(500).json({
            error: "Error interno del servidor",
            message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
        });
    }
}

async function get_online_stores(req, res, dbcentral) {
    try {
        const filter = req.query.filter; // 'online', 'offline', 'all' (default: 'all')
        const id_cliente = req.query.id_cliente; // Filtro opcional por cliente

        // Construir la consulta base
        let whereClause = "WHERE h.process_name = 'sql_inyector'";
        const replacements = [];

        // Filtrar por cliente si se proporciona
        if (id_cliente) {
            whereClause += " AND h.id_cliente = ?";
            replacements.push(id_cliente);
        }

        // Obtenemos los locales y su último ping
        // Consideramos "ONLINE" si el ping fue hace menos de 2 minutos
        const [results] = await dbcentral.query(
            `SELECT 
                h.store_id,
                h.id_cliente,
                h.instance_id,
                h.last_ping,
                h.status,
                h.extra_info,
                TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) as seconds_since_ping,
                CASE 
                    WHEN TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) <= 120 THEN 'ONLINE'
                    WHEN TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) <= 300 THEN 'DEGRADED'
                    ELSE 'OFFLINE'
                END as connectivity
             FROM tb_store_process_heartbeat h
             ${whereClause}
             ORDER BY h.last_ping DESC`,
            { replacements }
        );

        // Aplicar filtro de conectividad si se especifica
        let filteredResults = results;
        if (filter === 'online') {
            filteredResults = results.filter(r => r.connectivity === 'ONLINE');
        } else if (filter === 'offline') {
            filteredResults = results.filter(r => r.connectivity === 'OFFLINE' || r.connectivity === 'DEGRADED');
        }

        // Formatear la respuesta
        const formattedResults = filteredResults.map(store => ({
            store_id: store.store_id,
            id_cliente: store.id_cliente,
            instance_id: store.instance_id,
            connectivity: store.connectivity,
            status: store.status,
            last_ping: store.last_ping,
            seconds_since_ping: store.seconds_since_ping,
            extra_info: store.extra_info
        }));

        res.status(200).json({
            total: formattedResults.length,
            filter_applied: filter || 'all',
            stores: formattedResults
        });
    } catch (error) {
        console.error("❌ Error al obtener tiendas online:", error.message);
        res.status(500).json({
            error: "Error interno del servidor",
            message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
        });
    }
}

export { sql_inyec, save_result_inyec, create_command, get_command_status, get_commands_by_user, get_online_stores };
