<?php Session::init(); ?>
<?php
require_once 'models/kardex_model.php';
require_once 'models/PseModel.php';
class Venta_Model extends Model
{
    public function __construct()
    {
        parent::__construct();
    }

    public function Salon()
    {
        try {
            return $this->db->selectAll('SELECT * FROM tm_salon WHERE estado <> "i"');
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function Mozo()
    {
        try {
            return $this->db->selectAll('SELECT id_usu,nombres,ape_paterno,ape_materno FROM v_usuarios WHERE id_rol = 5 AND estado = "a"');
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function Repartidor()
    {
        try {
            return $this->db->selectAll('SELECT * FROM tm_usuario WHERE id_rol = 6 AND estado = "a"');
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function TipoDocumento()
    {
        try {
            return $this->db->selectAll('SELECT * FROM tm_tipo_doc WHERE estado = "a"');
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function TipoPago()
    {
        try {
            return $this->db->selectAll('SELECT * FROM tm_tipo_pago WHERE estado = "a"');
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function Personal()
    {
        try {
            return $this->db->selectAll("SELECT * FROM tm_usuario WHERE id_usu <> 1 AND estado = 'a' GROUP BY dni");
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function mesa_list()
    {
        try {
            $mesa = $this->db->prepare("SELECT * FROM v_listar_mesas ORDER BY id_mesa ASC");
            $mesa->execute();
            $m = $mesa->fetchAll(PDO::FETCH_OBJ);

            foreach ($m as $k => $d) {
                if ($d->id_pedido) {
                    $id_usu = $this->db->query("SELECT id_mozo FROM tm_pedido_mesa WHERE id_pedido =" . $d->id_pedido)->fetch(PDO::FETCH_COLUMN);
                    $m[$k]->{'Mozo'} = $this->db->query("SELECT nombres as nombre_mozo FROM v_usuarios WHERE id_usu =" . $id_usu)->fetch(PDO::FETCH_OBJ);
                }

            }

            $data = array("mesa" => $m);
            return $data;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function comensal()
    {
        try {
            $mesa = $this->db->prepare("SELECT SUM(nro_personas) as total_comen FROM v_listar_mesas WHERE estado!='a' ORDER BY id_mesa ASC");
            $mesa->execute();
            $m = $mesa->fetchColumn();
            return $m;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function mostrador_list($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date('Y-m-d');

            if ($data['estado'] == 'd') {
                $filtro_fecha = " AND DATE_FORMAT(p.fecha_pedido,'%Y-%m-%d') = '" . $fecha . "' ORDER BY p.fecha_pedido DESC";
            } else {
                $filtro_fecha = "";
            }

            $stm = $this->db->prepare("SELECT tp.*,p.fecha_pedido,p.estado,DATE(p.fecha_pedido) AS fecha FROM tm_pedido AS p INNER JOIN tm_pedido_llevar AS tp ON p.id_pedido = tp.id_pedido WHERE p.estado = ? " . $filtro_fecha);
            $stm->execute(array($data['estado']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Total'} = $this->db->query("SELECT IFNULL(SUM(precio*cantidad),0) AS total FROM v_det_llevar WHERE estado <> 'z' AND id_pedido = " . $d->id_pedido)
                    ->fetch(PDO::FETCH_OBJ);
            }
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function mostrador_list_c($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date('Y-m-d');

            if ($data['estado'] == 'd') {
                $filtro_fecha = " AND DATE_FORMAT(p.fecha_pedido,'%Y-%m-%d') = '" . $fecha . "' ORDER BY p.fecha_pedido DESC";
            } else {
                $filtro_fecha = "";
            }

            if (Session::get('rol') == 5) {

                $sql = "
                    SELECT
                    tp.*,
                    p.fecha_pedido,
                    p.estado,
                    DATE(p.fecha_pedido)          AS fecha,
                    v.id_venta,
                    v.id_tipo_pago,
                    IFNULL(v.total + v.comision_delivery - v.descuento_monto, 0) AS total
                    FROM tm_pedido           AS p
                    INNER JOIN tm_pedido_llevar AS tp ON tp.id_pedido = p.id_pedido
                    INNER JOIN tm_venta         AS v  ON v.id_pedido  = p.id_pedido
                    WHERE
                    p.estado = ? AND tp.canal = 'venta_normal'
                    $filtro_fecha
                ";

                $stm = $this->db->prepare($sql);
                $stm->execute([$data['estado']]);
                $c = $stm->fetchAll(PDO::FETCH_OBJ);


            } else {

                $sql = "
                    SELECT 
                        tp.*,
                        p.fecha_pedido,
                        p.estado,
                        DATE(p.fecha_pedido) AS fecha,
                        (
                        SELECT IFNULL(SUM(dp.cant * dp.precio), 0)
                        FROM tm_detalle_pedido dp
                        WHERE dp.id_pedido = p.id_pedido
                        ) AS total
                    FROM tm_pedido p
                    INNER JOIN tm_pedido_llevar tp ON p.id_pedido = tp.id_pedido
                    WHERE 
                        p.id_apc = ?
                        AND (p.estado = ? OR p.estado = 'c')
                        AND tp.canal = 'venta_normal'
                        $filtro_fecha
                    ";


                $stm = $this->db->prepare($sql);

                // Ejecutar con parámetros seguros
                $stm->execute([
                    Session::get('apcid'),     // ID del APC (sucursal)
                    $data['estado']            // Estado del pedido (ej. 'b')
                ]);

                // Obtener resultados como objetos
                $c = $stm->fetchAll(PDO::FETCH_OBJ);

            }


            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function mostrador_list_venta_rapida($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date('Y-m-d');

            if ($data['estado'] == 'd') {
                $filtro_fecha = " AND DATE_FORMAT(p.fecha_pedido,'%Y-%m-%d') = '" . $fecha . "' ORDER BY p.fecha_pedido DESC";
            } else {
                $filtro_fecha = "";
            }

            if (Session::get('rol') == 5) {

                $sql = "
                    SELECT
                    tp.*,
                    p.fecha_pedido,
                    p.estado,
                    DATE(p.fecha_pedido)          AS fecha,
                    v.id_venta,
                    v.id_tipo_pago,
                    DATE(p.fecha_pedido) AS fecha,
                        (
                            SELECT IFNULL(
                                    SUM(
                                    (CASE 
                                        WHEN p.estado = 'b' THEN COALESCE(dp.cantidad, 0)
                                        ELSE COALESCE(dp.cant, 0)
                                        END) * COALESCE(dp.precio, 0)
                                    ),
                                    0
                                )
                            FROM tm_detalle_pedido dp
                            WHERE dp.id_pedido = p.id_pedido
                        ) AS total
                    FROM tm_pedido           AS p
                    INNER JOIN tm_pedido_llevar AS tp ON tp.id_pedido = p.id_pedido
                    INNER JOIN tm_venta         AS v  ON v.id_pedido  = p.id_pedido
                    WHERE
                    p.estado = ? AND tp.canal = 'venta_rapida'
                    $filtro_fecha
                    ORDER BY p.id_pedido DESC
                ";

                $stm = $this->db->prepare($sql);
                $stm->execute([$data['estado']]);
                $c = $stm->fetchAll(PDO::FETCH_OBJ);


            } else {

                $sql = "
                    SELECT 
                        tp.*,
                        p.fecha_pedido,
                        p.estado,
                        DATE(p.fecha_pedido) AS fecha,
                        (
                            SELECT IFNULL(
                                    SUM(
                                    (CASE 
                                        WHEN p.estado = 'b' THEN COALESCE(dp.cantidad, 0)
                                        ELSE COALESCE(dp.cant, 0)
                                        END) * COALESCE(dp.precio, 0)
                                    ),
                                    0
                                )
                            FROM tm_detalle_pedido dp
                            WHERE dp.id_pedido = p.id_pedido AND dp.estado <> 'z'
                        ) AS total
                    FROM tm_pedido p
                    INNER JOIN tm_pedido_llevar tp ON p.id_pedido = tp.id_pedido
                    WHERE 
                        p.id_apc = ?
                        AND (p.estado = ? OR p.estado = 'c' OR p.estado = 'd')
                        AND tp.canal = 'venta_rapida'
                        $filtro_fecha
                    ORDER BY p.id_pedido DESC
                    ";


                $stm = $this->db->prepare($sql);

                $apcid = Session::get('apcid') ?? 1;

                // Ejecutar con parámetros seguros
                $stm->execute([
                    $apcid,     // ID del APC (sucursal)
                    $data['estado']            // Estado del pedido (ej. 'b')
                ]);

                // Obtener resultados como objetos
                $c = $stm->fetchAll(PDO::FETCH_OBJ);

            }


            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function delivery_list($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date('Y-m-d');

            if ($data['estado'] == 'd') {
                $filtro_fecha = " AND DATE_FORMAT(p.fecha_pedido,'%Y-%m-%d') = '" . $fecha . "' ORDER BY p.fecha_pedido DESC";
            } else {
                $filtro_fecha = "";
            }

            $stm = $this->db->prepare("SELECT tp.*,p.fecha_pedido,p.estado,DATE(p.fecha_pedido) AS fecha FROM tm_pedido AS p INNER JOIN tm_pedido_delivery AS tp ON p.id_pedido = tp.id_pedido WHERE p.estado = ? " . $filtro_fecha);
            $stm->execute(array($data['estado']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Tipopago'} = $this->db->query("SELECT descripcion AS nombre FROM tm_tipo_pago WHERE id_tipo_pago = " . $d->tipo_pago)
                    ->fetch(PDO::FETCH_OBJ);
            }
            foreach ($c as $k => $d) {
                // suma si hay delivery 
                // SELECT comision_delivery FROM `tm_pedido_delivery` WHERE `id_pedido` = 4
                $comisiondelivery = $this->db->query("SELECT comision_delivery FROM `tm_pedido_delivery` WHERE `id_pedido` =" . $d->id_pedido)->fetch();
                // $row = $result->fetch(PDO::FETCH_ASSOC);
                $ventatotal = $this->db->query("SELECT IFNULL(SUM(precio*cantidad),0) AS total FROM v_det_delivery WHERE estado <> 'z' AND id_pedido = " . $d->id_pedido)->fetch();



                $c[$k]->{'Total'} = $ventatotal;
            }
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function delivery_list_c($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date('Y-m-d');

            if ($data['estado'] == 'd') {
                $filtro_fecha = " AND DATE_FORMAT(p.fecha_pedido,'%Y-%m-%d') = '" . $fecha . "' ORDER BY p.fecha_pedido DESC";
            } else {
                $filtro_fecha = "";
            }

            $stm = $this->db->prepare("SELECT v.id_venta,tp.*,p.fecha_pedido,p.estado,DATE(p.fecha_pedido) AS fecha, v.id_tipo_pago AS tipo_pago_new, IFNULL((v.total+v.comision_delivery-v.descuento_monto),0) AS total FROM tm_pedido AS p INNER JOIN tm_pedido_delivery AS tp ON p.id_pedido = tp.id_pedido INNER JOIN tm_venta AS v ON p.id_pedido = v.id_pedido WHERE v.id_apc = ? AND p.estado = ? " . $filtro_fecha);
            $stm->execute(array(Session::get('apcid'), $data['estado']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Tipopago'} = $this->db->query("SELECT descripcion AS nombre FROM tm_tipo_pago WHERE id_tipo_pago = " . $d->tipo_pago_new)
                    ->fetch(PDO::FETCH_OBJ);
            }
            /*
            foreach($c as $k => $d)
            {
                $c[$k]->{'Total'} = $this->db->query("SELECT IFNULL(SUM(precio*cantidad),0) AS total FROM v_det_delivery WHERE estado <> 'z' AND id_pedido = " . $d->id_pedido)
                    ->fetch(PDO::FETCH_OBJ);
            }            
            */
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }
    /*
    public function delivery_list_b()
    {
        try
        {   
            $stm = $this->db->prepare("SELECT tp.*,p.fecha_pedido,p.estado,DATE(p.fecha_pedido) AS fecha FROM tm_pedido AS p INNER JOIN tm_pedido_delivery AS tp ON p.id_pedido = tp.id_pedido WHERE p.estado = 'x'");
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach($c as $k => $d)
            {
                $c[$k]->{'Total'} = $this->db->query("SELECT IFNULL(SUM(precio*cantidad),0) AS total FROM v_det_delivery WHERE estado <> 'i' AND id_pedido = " . $d->id_pedido)
                    ->fetch(PDO::FETCH_OBJ);
            }
            foreach($c as $k => $d)
            {
                $c[$k]->{'Repartidor'} = $this->db->query("SELECT descripcion AS nombre FROM tm_repartidor WHERE id_repartidor = " . $d->id_repartidor)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        }
        catch(Exception $e)
        {
            die($e->getMessage());
        }
    }

    public function delivery_list_c()
    {
        try
        {   
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL,"es_ES@euro","es_ES","esp");
            $fecha = date('Y-m-d');
            $stm = $this->db->prepare("SELECT tp.*,p.fecha_pedido,p.estado,DATE(p.fecha_pedido) AS fecha FROM tm_pedido AS p INNER JOIN tm_pedido_delivery AS tp ON p.id_pedido = tp.id_pedido WHERE p.estado = 'c' AND DATE_FORMAT(p.fecha_pedido,'%Y-%m-%d') = ?");
            $stm->execute(array($fecha));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach($c as $k => $d)
            {
                $c[$k]->{'Total'} = $this->db->query("SELECT IFNULL(SUM(precio*cantidad),0) AS total FROM v_det_delivery WHERE estado <> 'i' AND id_pedido = " . $d->id_pedido)
                    ->fetch(PDO::FETCH_OBJ);
            }
            foreach($c as $k => $d)
            {
                $c[$k]->{'Repartidor'} = $this->db->query("SELECT descripcion AS nombre FROM tm_repartidor WHERE id_repartidor = " . $d->id_repartidor)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        }
        catch(Exception $e)
        {
            die($e->getMessage());
        }
    }
    */

    public function listarPedidos($data)
    {
        try {
            if ($data['codpagina'] == '1') {
                $stm = $this->db->prepare("SELECT dp.id_pedido, dp.id_pres, SUM(dp.cantidad) AS cantidad, dp.precio, dp.comentario,p.nombre_cliente, dp.estado, p.nombre_mozo, p.fecha_pedido, p.estado_pedido, p.id_cliente,p.id_cliente,p.id_cliente,p.tipo_cliente,p.cliente_dni,p.cliente_ruc,p.cliente_nombres, p.cliente_razon_social FROM tm_detalle_pedido AS dp INNER JOIN v_pedido_mesa AS p ON p.id_pedido = dp.id_pedido WHERE dp.id_pedido = ? AND dp.estado <> 'z' AND dp.cantidad > 0 GROUP BY dp.id_pres, dp.precio ORDER BY dp.fecha_pedido DESC");
            } else {
                $stm = $this->db->prepare("SELECT dp.id_pedido, dp.id_pres, SUM(dp.cantidad) AS cantidad, dp.precio, dp.comentario, dp.estado FROM tm_detalle_pedido AS dp WHERE dp.id_pedido = ? AND dp.estado <> 'z' AND dp.cantidad > 0 GROUP BY dp.id_pres, dp.precio ORDER BY dp.fecha_pedido DESC");
            }
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            if (!$c) {
                throw new Exception("Pedido no encontrado.");
            }
            foreach ($c as $k => $d) {
                $c[$k]->{'Producto'} = $this->db->query("SELECT pro_nom,pro_pre,impuesto_icbper FROM v_productos WHERE id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarPedidosDetalle($data)
    {
        try {
            if ($data['cod_atencion'] == 2) {
                $tabla = 'v_pedido_llevar';
            } elseif ($data['cod_atencion'] == 3) {
                $tabla = 'v_pedido_delivery';
            }
            $stm = $this->db->prepare("SELECT * FROM " . $tabla . " WHERE id_pedido = ?");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetch(PDO::FETCH_OBJ);

            if (!$c) {
                throw new Exception("Pedido no encontrado.");
            }


            if ($c->estado_pedido == "b") {
                $c->{'Detalle'} = $this->db->query("SELECT id_pedido,id_pres,SUM(cantidad) AS cant, precio, comentario, estado FROM tm_detalle_pedido WHERE id_pedido = " . $c->id_pedido . " AND estado <> 'z' AND cantidad > 0 GROUP BY id_pres, precio ORDER BY fecha_pedido DESC")
                    ->fetchAll(PDO::FETCH_OBJ);
            } else {
                $c->{'Detalle'} = $this->db->query("SELECT id_pedido,id_pres,SUM(cant) AS cant, precio, comentario, estado FROM tm_detalle_pedido WHERE id_pedido = " . $c->id_pedido . " AND estado <> 'z' AND cant > 0 GROUP BY id_pres, precio ORDER BY fecha_pedido DESC")
                    ->fetchAll(PDO::FETCH_OBJ);
            }

            foreach ($c->Detalle as $k => $d) {
                $c->Detalle[$k]->{'Producto'} = $this->db->query("SELECT pro_nom,pro_pre FROM v_productos WHERE id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }

            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarUpdatePedidos($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");

            $stm = $this->db->prepare("SELECT p.pro_nom AS producto, p.pro_pre AS presentacion, SUM(d.cant) AS cantidad, d.precio, d.comentario, a.id_areap, i.nombre AS nombre_imp FROM tm_detalle_pedido AS d INNER JOIN v_productos AS p ON d.id_pres = p.id_pres INNER JOIN tm_area_prod AS a ON a.id_areap = p.id_areap INNER JOIN tm_impresora AS i ON i.id_imp = a.id_imp WHERE d.id_pedido = ? AND d.estado = 'y' AND d.cant > 0 GROUP BY d.id_pres ORDER BY d.fecha_pedido DESC");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);

            $sql2 = "UPDATE tm_detalle_pedido SET estado = 'a', fecha_pedido = ? WHERE id_pedido = ? AND estado = 'y'";
            $this->db->prepare($sql2)->execute(array($fecha, $data['id_pedido']));

            if ($data['estado_pedido'] == 'a') {

                $sql3 = "UPDATE tm_pedido SET id_apc = ?, id_usu = ?, estado = 'b' WHERE id_pedido = ?";
                $this->db->prepare($sql3)->execute(array(Session::get('apcid'), Session::get('usuid'), $data['id_pedido']));

                $sql4 = "UPDATE tm_pedido_delivery SET fecha_preparacion = ? WHERE id_pedido = ?";
                $this->db->prepare($sql4)->execute(array($fecha, $data['id_pedido']));
                /*
                UPDATE tm_pedido SET id_apc = _id_apc, id_usu = _id_usu, estado = 'b' WHERE id_pedido = _id_pedido;
                UPDATE tm_pedido_delivery SET fecha_preparacion = _fecha_venta WHERE id_pedido = _id_pedido;
                */
            }

            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function reimpresion_comanda($data)
    {
        try {

            $stmkey = $this->db->prepare("SELECT * FROM tm_comandas WHERE id_key = '{$data['id_key']}'");
            $stmkey->execute();
            $ckey = $stmkey->fetch(PDO::FETCH_OBJ);

            $stm = $this->db->prepare("SELECT p.pro_cat AS categoria,p.id_pres AS producto_id, p.pro_nom AS producto, p.pro_pre AS presentacion, SUM(d.cant) AS cantidad, d.precio, d.comentario, a.id_areap, i.nombre AS nombre_imp FROM tm_detalle_pedido AS d INNER JOIN v_productos AS p ON d.id_pres = p.id_pres INNER JOIN tm_area_prod AS a ON a.id_areap = p.id_areap INNER JOIN tm_impresora AS i ON i.id_imp = a.id_imp WHERE d.id_pedido = ? AND d.fecha_pedido = ?  AND d.cant > 0 GROUP BY d.id_pres ORDER BY d.fecha_pedido DESC");
            $stm->execute(array($ckey->id_pedido, $ckey->fecha_pedido));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);


            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarPedidosTicket($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");

            $stm = $this->db->prepare("SELECT p.pro_nom AS producto, p.pro_pre AS presentacion, SUM(d.cant) AS cantidad, d.precio, d.comentario, 1 AS id_areap, 'CAJA' AS nombre_imp FROM tm_detalle_pedido AS d INNER JOIN v_productos AS p ON d.id_pres = p.id_pres WHERE d.id_pedido = ? AND d.estado = 'a' AND d.cant > 0 GROUP BY d.id_pres ORDER BY d.fecha_pedido DESC");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);

            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function pedidoAccion($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");

            if ($data['cod_accion'] == 1) {
                $estado = 'c';
                $tabla = 'tm_pedido_delivery';
                $fecha_campo = 'fecha_envio';
            } else if ($data['cod_accion'] == 2) {
                $estado = 'd';
                $tabla = 'tm_pedido_delivery';
                $fecha_campo = 'fecha_entrega';
            } else if ($data['cod_accion'] == 3) {
                $estado = 'd';
                $tabla = 'tm_pedido_llevar';
                $fecha_campo = 'fecha_entrega';
            }

            $sql = "UPDATE tm_pedido SET estado = '" . $estado . "' WHERE id_pedido = ?";
            $this->db->prepare($sql)->execute(array($data['id_pedido']));
            $sql2 = "UPDATE " . $tabla . " SET " . $fecha_campo . " = ? WHERE id_pedido = ?";
            $this->db->prepare($sql2)->execute(array($fecha, $data['id_pedido']));
            $sql3 = "UPDATE tm_venta SET codigo_operacion = ? WHERE id_pedido = ?";
            $this->db->prepare($sql3)->execute(array($data['codigo_operacion'], $data['id_pedido']));

        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function ComboMesaOri($data)
    {
        try {
            $stmm = $this->db->prepare("SELECT * FROM tm_mesa WHERE id_salon = ? AND estado = 'i' ORDER BY nro_mesa ASC");
            $stmm->execute(array($data['cod_salon_origen']));
            $var = $stmm->fetchAll(PDO::FETCH_ASSOC);
            foreach ($var as $v) {
                echo '<option value="' . $v['id_mesa'] . '">' . $v['nro_mesa'] . '</option>';
            }
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function ComboMesaDes($data)
    {
        try {
            $stmm = $this->db->prepare("SELECT * FROM tm_mesa WHERE id_salon = ? AND estado = ? ORDER BY nro_mesa ASC");
            $stmm->execute(array($data['cod_salon_destino'], $data['estado']));
            $var = $stmm->fetchAll(PDO::FETCH_ASSOC);
            foreach ($var as $v) {
                echo '<option value="' . $v['id_mesa'] . '">' . $v['nro_mesa'] . '</option>';
            }
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function CambiarMesa($data)
    {
        try {
            $consulta = "call usp_restOpcionesMesa( :flag, :cod_mesa_origen, :cod_mesa_destino);";
            $arrayParam = array(
                ':flag' => 1,
                ':cod_mesa_origen' => $data['cod_mesa_origen_opc01'],
                ':cod_mesa_destino' => $data['cod_mesa_destino_opc01']
            );
            $st = $this->db->prepare($consulta);
            $st->execute($arrayParam);
            $row = $st->fetch(PDO::FETCH_ASSOC);
            return $row;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function MoverPedidos($data)
    {
        try {
            $consulta = "call usp_restOpcionesMesa( :flag, :cod_mesa_origen, :cod_mesa_destino);";
            $arrayParam = array(
                ':flag' => 2,
                ':cod_mesa_origen' => $data['cod_mesa_origen_opc02'],
                ':cod_mesa_destino' => $data['cod_mesa_destino_opc02']
            );
            $st = $this->db->prepare($consulta);
            $st->execute($arrayParam);
            $row = $st->fetch(PDO::FETCH_ASSOC);
            return $row;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function subPedido($data)
    {
        try {
            if ($data['tipo_pedido'] == 1) {
                $tabla = 'v_pedido_mesa';
            } elseif ($data['tipo_pedido'] == 2) {
                $tabla = 'v_pedido_llevar';
            } elseif ($data['tipo_pedido'] == 3) {
                $tabla = 'v_pedido_delivery';
            }
            $stm = $this->db->prepare("SELECT id_pedido, id_tipo_pedido, estado_pedido FROM " . $tabla . " WHERE id_pedido = ?");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetch(PDO::FETCH_OBJ);
            /* Traemos el detalle */
            $c->{'Detalle'} = $this->db->query("SELECT id_pres, cantidad, cant, precio, comentario, estado, fecha_pedido FROM tm_detalle_pedido WHERE id_pedido = " . $c->id_pedido . " AND id_pres = " . $data['id_pres'] . " AND precio = " . $data['precio'] . " ORDER BY fecha_pedido DESC")
                ->fetchAll(PDO::FETCH_OBJ);
            foreach ($c->Detalle as $k => $d) {
                $c->Detalle[$k]->{'Producto'} = $this->db->query("SELECT pro_nom,pro_pre FROM v_productos WHERE id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            $errorMessage = "Error: " . $e->getMessage() . " en el archivo " . $e->getFile() . " en la línea " . $e->getLine();
            error_log($errorMessage); // Guarda el error en el log del servidor
            die($errorMessage);
        }
    }

    public function detallesPedido(array $data)
    {
        try {

            if (!isset($data['tipo_pedido'], $data['id_pedido'])) {
                throw new \InvalidArgumentException('Faltan parámetros requeridos.');
            }


            switch ($data['tipo_pedido']) {
                case 1:
                    $tabla = 'v_pedido_mesa';
                    break;
                case 2:
                    $tabla = 'v_pedido_llevar';
                    break;
                case 3:
                    $tabla = 'v_pedido_delivery';
                    break;
                default:
                    throw new \InvalidArgumentException('Tipo de pedido inválido.');
            }

            $sqlPedido = "SELECT id_pedido, id_tipo_pedido, estado_pedido FROM {$tabla} WHERE id_pedido = ?";
            $stmPedido = $this->db->prepare($sqlPedido);
            $stmPedido->execute(array($data['id_pedido']));
            $pedido = $stmPedido->fetch(PDO::FETCH_OBJ);

            if (!$pedido) {
                throw new \RuntimeException("Pedido no encontrado para el id_pedido {$data['id_pedido']}.");
            }

            $sqlDetalle = "SELECT id_pres, cantidad, cant, precio, comentario, estado, fecha_pedido
                       FROM tm_detalle_pedido
                       WHERE id_pedido = ?
                       ORDER BY fecha_pedido DESC";
            $stmDetalle = $this->db->prepare($sqlDetalle);
            $stmDetalle->execute(array($pedido->id_pedido));
            $pedido->Detalle = $stmDetalle->fetchAll(PDO::FETCH_OBJ);

            $sqlProducto = "SELECT pro_nom, pro_pre FROM v_productos WHERE id_pres = ?";
            $stmProducto = $this->db->prepare($sqlProducto);

            foreach ($pedido->Detalle as $key => $detalle) {
                $stmProducto->execute(array($detalle->id_pres));
                $pedido->Detalle[$key]->Producto = $stmProducto->fetch(PDO::FETCH_OBJ);
            }

            return $pedido;
        } catch (\Exception $e) {
            // Construir un mensaje de error detallado
            $errorMessage = sprintf(
                "Error: %s en %s en la línea %d",
                $e->getMessage(),
                $e->getFile(),
                $e->getLine()
            );
            error_log($errorMessage); // Registrar el error
            throw new \Exception($errorMessage);
        }
    }



    public function cancelarPedido($data)
    {
        try {
            $pedido = $this->detallesPedido($data);
            if (!$pedido || empty($pedido->Detalle)) {
                throw new Exception("No se encontró el pedido o no tiene detalles.");
            }

            $detalleProductos = array_map(function ($item) {
                return [
                    'id_pres' => $item->id_pres,
                    'estado_pedido' => $item->estado,
                    'fecha_pedido' => $item->fecha_pedido
                ];
            }, $pedido->Detalle);

            $json_productos = json_encode($detalleProductos);
            if ($json_productos === false) {
                throw new Exception("Error al codificar a JSON: " . json_last_error_msg());
            }

            error_log("JSON de productos: " . $json_productos);

            $response = [
                'success' => true,
                'message' => 'Stock repuesto correctamente',
                'data' => null,
            ];


            $pseModel = new PseModel();
            $rs = $pseModel->reponerStock($data['id_pedido']);

            // Normaliza posibles formatos de salida del modelo
            if (is_array($rs)) {
                // Caso legacy: ['skipped' => true, 'msg' => 'Venta sin detalles']
                if (isset($rs['skipped']) && $rs['skipped'] === true) {
                    // No es error: solo informa que no había nada que reponer
                    $response['message'] .= ' (Sin reposición: ' . ($rs['msg'] ?? 'venta sin detalles') . ')';
                }
                // Caso moderno: { ok: true|false, ... }
                elseif (array_key_exists('ok', $rs)) {
                    if ($rs['ok'] === false) {
                        // Si deseas considerar esto como error global:
                        http_response_code(500);
                        echo json_encode([
                            'success' => false,
                            'message' => $rs['message'] ?? 'Error al reponer stock',
                            'data' => $rs,
                        ], JSON_UNESCAPED_UNICODE);
                        return;
                    }
                    // ok === true → opcionalmente agrega info al mensaje
                    if (!empty($rs['message'])) {
                        $response['message'] .= ' — ' . $rs['message'];
                    }
                }
                // Otro formato inesperado → adjunta como data informativa
                else {
                    $response['data'] = $rs;
                }
            }

            $consulta = "CALL usp_cancelarProductosPedido(
            :flag,
            :id_pedido,
            :id_usu,
            :codigo_seguridad,
            :filtro_seguridad,
            :productos
        )";

            $stmt = $this->db->prepare($consulta);
            $params = [
                ':flag' => 1,
                ':id_pedido' => $data['id_pedido'],
                ':id_usu' => Session::get('usuid'),
                ':codigo_seguridad' => $data['codigo_seguridad'],
                ':filtro_seguridad' => $data['filtro_seguridad'],
                ':productos' => $json_productos,
            ];

            if (!$stmt->execute($params)) {
                $errorInfo = $stmt->errorInfo();
                error_log("Error al ejecutar el procedure: " . $errorInfo[2]);
                return ["error" => $errorInfo[2]];
            }

            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            while ($stmt->nextRowset()) {
            } // importante para limpiar resultsets
            $stmt->closeCursor();

            if (!$result || (int) $result['resultado'] !== 1) {
                return ["error" => "El procedimiento no se ejecutó correctamente."];
            }


            // foreach ($pedido->Detalle as $item) {
            //     $id_pres = (int) $item->id_pres;
            //     $cantidad = (float) $item->cant;

            //     $stm_pres = $this->db->prepare("
            //     SELECT receta, crt_stock 
            //     FROM tm_producto_pres 
            //     WHERE id_pres = ? LIMIT 1
            // ");
            //     $stm_pres->execute([$id_pres]);
            //     $presentacion = $stm_pres->fetch(PDO::FETCH_OBJ);

            //     if ($presentacion && $presentacion->crt_stock == 1) {
            //         if ($presentacion->receta == 1) {
            //             $stmt_ingr = $this->db->prepare("
            //             SELECT id_ins, cant 
            //             FROM tm_producto_ingr 
            //             WHERE id_pres = ?
            //         ");
            //             $stmt_ingr->execute([$id_pres]);
            //             $ingredientes = $stmt_ingr->fetchAll(PDO::FETCH_OBJ);

            //             foreach ($ingredientes as $ing) {
            //                 $cantidad_reponer = $ing->cant * $cantidad;
            //                 //$this->restablecerInventario($this->db, $ing->id_ins, $cantidad_reponer);
            //                 error_log("Repuesto ingrediente ID {$ing->id_ins}, cantidad {$cantidad_reponer}");
            //             }
            //         } else {
            //             //$this->restablecerInventario($this->db, $id_pres, $cantidad);
            //             error_log("Repuesto producto ID {$id_pres}, cantidad {$cantidad}");
            //         }
            //     }
            // }


            return $result;

        } catch (Exception $e) {
            error_log("Error en cancelarPedido: " . $e->getMessage());
            return ["error" => $e->getMessage()];
        }
    }


    public function actualizarDataDelivery($data)
    {
        try {
            // Convertir "" a NULL para hora_entrega
            $hora = trim($data['hora_entrega']) === '' ? null : $data['hora_entrega'];
            $comision = (float) $data['comision_delivery'];

            $stm = $this->db->prepare("
            UPDATE tm_pedido_delivery SET
                id_repartidor = ?,
                tipo_entrega = ?,
                hora_entrega = ?,
                comision_delivery = ?,
                nombre_cliente = ?,
                telefono_cliente = ?,
                direccion_cliente = ?,
                referencia_cliente = ?
            WHERE id_pedido = ?
        ");

            $ok = $stm->execute([
                $data['id_repartidor'],
                $data['tipo_entrega'],
                $hora,
                $comision,
                $data['nombre_cliente'],
                $data['telefono_cliente'],
                $data['direccion_cliente'],
                $data['referencia_cliente'],
                $data['id_pedido']
            ]);

            if (!$ok) {
                $errorInfo = $stm->errorInfo();
                return (object) [
                    'success' => false,
                    'message' => 'Error SQL: ' . $errorInfo[2]
                ];
            }

            return (object) [
                'success' => true,
                'message' => 'Datos actualizados correctamente'
            ];
        } catch (Exception $e) {
            return (object) [
                'success' => false,
                'message' => 'Error al actualizar: ' . $e->getMessage()
            ];
        }
    }

    public function refrescar_mesas()
    {
        try {
            $stm = $this->db->prepare("UPDATE tm_mesa AS m INNER JOIN v_listar_mesas AS v ON m.id_mesa = v.id_mesa SET m.estado = 'a' WHERE v.estado <> 'a' AND v.estado <> 'm' AND v.id_pedido IS NULL");
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            return false;
        }
    }

    public function ValidarEstadoPedido($id_pedido)
    {
        try {
            $consulta = "SELECT count(*) AS cod, id_tipo_pedido AS tipo_pedido FROM tm_pedido WHERE id_pedido = :id_pedido AND (estado = 'a' OR estado = 'b' OR estado ='c')";
            $result = $this->db->prepare($consulta);
            $result->bindParam(':id_pedido', $id_pedido, PDO::PARAM_INT);
            $result->execute();
            $row = $result->fetch(PDO::FETCH_ASSOC);
            return $row;
        } catch (Exception $e) {
            return false;
        }
    }

    // public function ValidarEstadoPedido($id_pedido)
    // {
    //     try {
    //         $consulta = "SELECT count(*) AS cod, id_tipo_pedido AS tipo_pedido FROM tm_pedido WHERE id_pedido = :id_pedido AND (estado = 'a' OR estado = 'b' OR estado ='c')";
    //         $result = $this->db->prepare($consulta);
    //         $result->bindParam(':id_pedido',$id_pedido,PDO::PARAM_INT);
    //         $result->execute();
    //         $row = $result->fetch(PDO::FETCH_ASSOC);
    //         return $row;
    //     } catch (Exception $e) {
    //         return false;
    //     }
    // }

    public function pc1($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");
            $id_usu = Session::get('usuid');
            if (Session::get('rol') == 5) {
                $id_mozo = $id_usu;
            } else {
                $id_mozo = $data['id_mozo'];
            }

            $consulta = "call usp_restRegMesa( :flag, :id_tipo_pedido, :id_apc, :id_usu, :fecha_pedido, :id_mesa, :id_mozo, :nomb_cliente, :nro_personas, :id_cliente);";
            $arrayParam = array(
                ':flag' => 1,
                ':id_tipo_pedido' => 1,
                ':id_apc' => Session::get('apcid') ?? 1,
                ':id_usu' => $id_usu,
                ':fecha_pedido' => $fecha,
                ':id_mesa' => $data['id_mesa'],
                ':id_mozo' => $id_mozo,
                ':nomb_cliente' => $data['nomb_cliente'],
                ':nro_personas' => $data['nro_personas'],
                ':id_cliente' => $data['cliente_id']
            );

            $st = $this->db->prepare($consulta);
            if (!$st->execute($arrayParam)) {
                // Si falla la ejecución, obtenemos información detallada del error
                $errorInfo = $st->errorInfo();
                error_log("Error al ejecutar el procedure: " . $errorInfo[2]); // Loguea el error en el servidor
                return array("error" => $errorInfo[2]);
            }

            $row = $st->fetch(PDO::FETCH_ASSOC);
            return $row;
        } catch (Exception $e) {
            // Capturamos y logueamos cualquier excepción
            error_log("Excepción: " . $e->getMessage());
            return array("error" => $e->getMessage());
        }
    }


    public function pc2($data)
    {

        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");
            $id_usu = Session::get('usuid');
            $consulta = "call usp_restRegMostrador( :flag, :id_tipo_pedido, :id_apc, :id_usu, :fecha_pedido, :nomb_cliente, :canal);";
            $arrayParam = array(
                ':flag' => 1,
                ':id_tipo_pedido' => 2,
                ':id_apc' => Session::get('apcid'),
                ':id_usu' => $id_usu,
                ':fecha_pedido' => $fecha,
                ':nomb_cliente' => $data['nomb_cliente'],
                ':canal' => (int) $data['canal'],

            );
            $st = $this->db->prepare($consulta);
            if (!$st->execute($arrayParam)) {
                // Si falla la ejecución, obtenemos información detallada del error
                $errorInfo = $st->errorInfo();
                error_log("Error al ejecutar el procedure: " . $errorInfo[2]); // Loguea el error en el servidor
                return array("error" => $errorInfo[2]);
            }
            $row = $st->fetch(PDO::FETCH_ASSOC);
            return $row;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function pc3($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");
            $id_usu = Session::get('usuid');
            if ($data['tipo_entrega'] == 1) {
                $id_repartidor = $data['id_repartidor'];
                $direccion_cliente = $data['direccion_cliente'];
                $referencia_cliente = $data['referencia_cliente'];
            } else {
                $id_repartidor = 1;
                $direccion_cliente = '';
                $referencia_cliente = '';
            }
            ;
            $consulta = "call usp_restRegDelivery( :flag, :tipo_canal, :id_tipo_pedido, :id_apc, :id_usu, :fecha_pedido, :id_cliente, :id_repartidor, :tipo_entrega, :tipo_pago, :pedido_programado, :hora_entrega, :nombre_cliente, :telefono_cliente, :direccion_cliente, :referencia_cliente, :email_cliente, :id_tdoc, :num_cliente);";
            $arrayParam = array(
                ':flag' => 1,
                ':tipo_canal' => 1,
                ':id_tipo_pedido' => 3,
                ':id_apc' => Session::get('apcid'),
                ':id_usu' => $id_usu,
                ':fecha_pedido' => $fecha,
                ':id_cliente' => $data['cliente_id'],
                ':id_repartidor' => $id_repartidor,
                ':tipo_entrega' => $data['tipo_entrega'],
                ':tipo_pago' => 1,
                ':pedido_programado' => isset($data['pedido_programado']) ? $data['pedido_programado'] : null,
                ':hora_entrega' => isset($data['hora_entrega']) ? $data['hora_entrega'] : null,
                ':nombre_cliente' => $data['nomb_cliente'],
                ':telefono_cliente' => $data['telefono_cliente'],
                ':direccion_cliente' => $direccion_cliente,
                ':referencia_cliente' => $referencia_cliente,
                ':email_cliente' => '' . $data['telefono_cliente'] . '@gmail.com',
                ':id_tdoc' => $data['id_tdoc'],
                ':num_cliente' => $data['num_cliente']
            );
            $st = $this->db->prepare($consulta);
            if (!$st->execute($arrayParam)) {
                // Si falla la ejecución, obtenemos información detallada del error
                $errorInfo = $st->errorInfo();
                error_log("Error al ejecutar el procedure: " . $errorInfo[2]); // Loguea el error en el servidor
                return array("error" => $errorInfo[2]);
            }
            $row = $st->fetch(PDO::FETCH_ASSOC);
            return $row;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function defaultdata($data)
    {
        try {
            if ($data['tipo_pedido'] == 1) {
                $tabla = 'v_pedido_mesa';
            } elseif ($data['tipo_pedido'] == 2) {
                $tabla = 'v_pedido_llevar';
            } elseif ($data['tipo_pedido'] == 3) {
                $tabla = 'v_pedido_delivery';
            }
            $stm = $this->db->prepare("SELECT * FROM " . $tabla . " WHERE id_pedido = ?");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetch(PDO::FETCH_OBJ);
            /* Traemos el detalle */
            $c->{'Detalle'} = $this->db->query("SELECT SUM(tdp.cantidad) AS cantidad, tdp.precio, tdp.comentario, tdp.estado, tpp.impuesto_icbper
                FROM tm_detalle_pedido tdp
                INNER JOIN tm_producto_pres tpp ON tpp.id_pres = tdp.id_pres
                WHERE tdp.id_pedido = " . $c->id_pedido . " AND tdp.estado <> 'z' GROUP BY tdp.id_pres,tdp.precio ORDER BY tdp.fecha_pedido DESC")
                ->fetchAll(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarCategorias($data)
    {
        try {
            $variable = ' ORDER BY orden ASC';
            $stm = $this->db->prepare("SELECT * FROM tm_producto_catg WHERE estado = 'a' " . $variable);
            $stm->execute();
            $categorias = $stm->fetchAll(PDO::FETCH_OBJ);

            foreach ($categorias as $k => $cat) {

                $data['id_catg'] = $cat->id_catg;
                $productos = $this->listarProductos($data);
                $categorias[$k]->productos = $productos;
            }

            return $categorias;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarProductos($data)
    {
        try {
            if ($data['codtipoped'] == 3) {
                if ($data['codrepartidor'] == 1) {
                    $campo = ',pro_cos,pro_cos2';
                    $variable = 'ORDER BY ordenins asc';
                } else {
                    $campo = ',pro_cos_del AS pro_cos,pro_cos2';
                    $variable = ' AND pro_cos_del > 0 ORDER BY ordenins asc';
                }
            } else {
                $campo = ',pro_cos,pro_cos2';
                $variable = 'ORDER BY ordenins asc';
            }
            $stm = $this->db->prepare("SELECT id_areap,id_pres,pro_cod,pro_imp,precios,pro_nom,pro_pre" . $campo . ",pro_img FROM v_productos WHERE id_catg = ? AND est_a = 'a'  AND est_b = 'a' AND est_c = 'a' " . $variable);
            $stm->execute(array($data['id_catg']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Impresora'} = $this->db->query("SELECT i.nombre FROM tm_area_prod AS ap INNER JOIN tm_impresora AS i ON ap.id_imp = i.id_imp WHERE ap.id_areap = " . $d->id_areap)
                    ->fetch(PDO::FETCH_OBJ);

                $stockQuery = $this->db->query("
                    SELECT 
                        p.receta,
                        p.stock_min,
                        p.crt_stock,
                        CASE 
                            WHEN p.receta = 1 THEN (
                                SELECT JSON_ARRAYAGG(
                                    JSON_OBJECT(
                                        'id_ins', i.id_ins,
                                        'id_med', i.id_med,
                                        'cant', i.cant,
                                        'principal', ip.ingrediente_principal,
                                        'stock_actual', (
                                            SELECT IFNULL(SUM(inv.stock), 0)
                                            FROM tm_insumo inv
                                            WHERE inv.id_ins = i.id_ins
                                        )
                                    )
                                )
                                FROM tm_producto_ingr i
                                LEFT JOIN tm_producto_ingr ip ON ip.id_ins = i.id_ins
                                WHERE i.id_pres = p.id_pres
                            )
                            ELSE (
                            SELECT JSON_ARRAYAGG(
                                JSON_OBJECT(
                                    'id_ins',       p2.id_pres,
                                    'principal',    'si',
                                    'stock_actual', p2.stock
                                )
                            )
                            FROM tm_producto_pres AS p2
                            WHERE p2.id_pres = {$d->id_pres}
                        )
                        END AS ingredientes
                    FROM tm_producto_pres p
                    WHERE p.id_pres = {$d->id_pres}
                    AND p.crt_stock = 1
                ");

                if ($stockQuery) {
                    $stock = $stockQuery->fetch(PDO::FETCH_OBJ);
                    $c[$k]->{'Stock'} = $stock ?: false;
                } else {
                    // Mostrar el error SQL (en desarrollo)
                    $errorInfo = $this->db->errorInfo();
                    error_log("Error en consulta de Stock para id_pres {$d->id_pres}: " . $errorInfo[2]);

                    // También puedes imprimirlo en pantalla si estás debuggeando:
                    echo "<pre>Error SQL: {$errorInfo[2]}</pre>";

                    $c[$k]->{'Stock'} = false;
                }

                $c[$k]->{'notas'} = $this->db->query("SELECT p.id_prod,p.notas FROM tm_producto AS p INNER JOIN tm_producto_pres AS pp ON p.id_prod = pp.id_prod WHERE pp.id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarProdsMasVend($data)
    {
        try {
            if ($data['codtipoped'] == 3) {
                if ($data['codrepartidor'] == 1) {
                    $campo = ',pro_cos,pro_cos2';
                    $variable = '';
                } else {
                    $campo = ',pro_cos_del AS pro_cos,pro_cos2';
                    $variable = ' AND pro_cos_del > 0 ';
                }
            } else {
                $campo = ',pro_cos,pro_cos2';
                $variable = '';
            }
            $stm = $this->db->prepare("SELECT id_areap,pro_cod,precios,id_pres,pro_nom,pro_pre" . $campo . ",pro_img FROM v_prod_favorito WHERE est_a = 'a' AND est_b = 'a' AND est_c = 'a' " . $variable);
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Impresora'} = $this->db->query("SELECT i.nombre FROM tm_area_prod AS ap INNER JOIN tm_impresora AS i ON ap.id_imp = i.id_imp WHERE ap.id_areap = " . $d->id_areap)
                    ->fetch(PDO::FETCH_OBJ);

                $c[$k]->{'Stock'} = $this->db->query("SELECT * FROM v_stock_pedido WHERE id_ins =" . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    // public function RegistrarPedido($data)
    // {
    //     try 
    //     {
    //         date_default_timezone_set($_SESSION["zona_horaria"]);
    //         setlocale(LC_ALL,"es_ES@euro","es_ES","esp");
    //         $fecha = date("Y-m-d H:i:s");
    //         $id_usu = Session::get('usuid');
    //         $key = md5(uniqid(rand(), true));
    //         if($data['codtipoped'] == 3){ 
    //             $estado = 'y';
    //         } else {
    //             $estado = 'a';
    //         } 
    //         foreach($data['items'] as $d)
    //         {
    //             $sql = "INSERT INTO tm_detalle_pedido (id_pedido, id_usu, id_pres, cantidad, cant, precio, comentario, fecha_pedido, estado) VALUES (?,?,?,?,?,?,?,?,?);";
    //             $this->db->prepare($sql)->execute(array($data['cod_ped'],$id_usu,$d['producto_id'],$d['cantidad'],$d['cantidad'],$d['precio'],$d['comentario'],$fecha,$estado));
    //         }
    //         $sql2 = "INSERT INTO tm_comandas (id_pedido, fecha_pedido, id_key) VALUES (?,?,?) ;";
    //         $this->db->prepare($sql2)->execute(array($data['cod_ped'],$fecha,$key));
    //     }
    //     catch (Exception $e) 
    //     {
    //         return false;
    //     }
    // }

    public function RegistrarPedido($data)
    {
        try {
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");
            $id_usu = Session::get('usuid');
            $key = md5(uniqid(rand(), true));
            //$estado = ($data['codtipoped'] == 3) ? 'y' : 'a';
            $estado = 'a';
            $errores = [];

            $ids = [];
            $cantidades = [];


            foreach ($data['items'] as $d) {
                try {
                    // Registrar detalle del producto
                    $sql = "INSERT INTO tm_detalle_pedido 
                            (id_pedido, id_usu, id_pres, cantidad, cant, precio, comentario, fecha_pedido, estado) 
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
                    $stmt = $this->db->prepare($sql);
                    $stmt->execute([
                        $data['cod_ped'],
                        $id_usu,
                        $d['producto_id'],
                        $d['cantidad'],
                        $d['cantidad'],
                        $d['precio'],
                        $d['comentario'],
                        $fecha,
                        $estado
                    ]);

                    $ids[] = $d['producto_id'];
                    $cantidades[] = $d['cantidad'];



                } catch (Exception $e) {
                    $errores[] = [
                        'producto_id' => $d['producto_id'],
                        'error' => $e->getMessage()
                    ];
                }
            }

            // Registrar comanda
            try {
                $sql2 = "INSERT INTO tm_comandas (id_pedido, fecha_pedido, id_key) VALUES (?, ?, ?)";
                $stmt2 = $this->db->prepare($sql2);
                $stmt2->execute([$data['cod_ped'], $fecha, $key]);
            } catch (Exception $e) {
                $errores[] = [
                    'comanda' => 'Error al insertar en tm_comandas',
                    'error' => $e->getMessage()
                ];
            }

            if (!empty($errores)) {
                return [
                    'status' => 'error',
                    'message' => 'Algunos productos o insumos no se pudieron registrar correctamente.',
                    'errors' => $errores
                ];
            }

            $this->updateStockProduct($ids, $cantidades);
            $this->detalleKardex($ids, $cantidades, "salida");

            return [
                'status' => 'success',
                'message' => 'Pedido registrado correctamente.',
                'pedido_id' => $data['cod_ped']
            ];
        } catch (Exception $e) {
            return [
                'status' => 'error',
                'message' => 'Error general al registrar el pedido.',
                'error' => $e->getMessage()
            ];
        }
    }

    public function descontarInventario($db, $id_ins, $cantidadDescontar)
    {
        try {
            $stmtInv = $db->prepare("SELECT id_inv, cant FROM tm_inventario 
                WHERE id_ins = ? AND cant > 0 AND estado = 'a' 
                ORDER BY fecha_r ASC");
            $stmtInv->execute([$id_ins]);
            $inventarios = $stmtInv->fetchAll(PDO::FETCH_OBJ);

            foreach ($inventarios as $inv) {
                if ($cantidadDescontar <= 0)
                    break;

                $restar = min($cantidadDescontar, $inv->cant);
                $nuevaCant = $inv->cant - $restar;

                $stmtUpd = $db->prepare("UPDATE tm_inventario SET cant = ? WHERE id_inv = ?");
                $stmtUpd->execute([$nuevaCant, $inv->id_inv]);

                $cantidadDescontar -= $restar;
            }

            return $cantidadDescontar <= 0;
        } catch (Exception $e) {
            return false;
        }
    }


    public function listarComandas($data)
    {
        try {
            $stm = $this->db->prepare("SELECT * FROM tm_comandas WHERE id_pedido = {$data['id_pedido']};");
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function buscar_producto($data)
    {
        try {
            if ($data['codtipoped'] == 3) {
                if ($data['codrepartidor'] == 1) {
                    $campo = ',pro_cos,pro_cos2';
                } else {
                    $campo = ',pro_cos_del AS pro_cos, pro_cos2';
                }
                $variable = 'AND del_a = 1 AND del_b = 1 AND del_c = 1 ORDER BY ordenins asc';
            } else {
                $variable = 'ORDER BY ordenins asc';
                $campo = ',pro_cos,pro_cos2 ';
            }
            $cadena = $data['cadena'];
            $stm = $this->db->prepare("SELECT id_areap,id_pres,pro_nom,precios,pro_cod,pro_pre" . $campo . ",pro_img FROM v_productos WHERE (pro_cod LIKE '%$cadena%' OR pro_pre LIKE '%$cadena%' OR pro_nom LIKE '%$cadena%' OR pro_cat LIKE '%$cadena%') AND est_a = 'a' AND est_b = 'a' AND est_c = 'a' " . $variable);
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Impresora'} = $this->db->query("SELECT i.nombre FROM tm_area_prod AS ap INNER JOIN tm_impresora AS i ON ap.id_imp = i.id_imp WHERE ap.id_areap = " . $d->id_areap)
                    ->fetch(PDO::FETCH_OBJ);

                $c[$k]->{'Stock'} = $this->db->query("SELECT * FROM v_stock_pedido WHERE id_ins =" . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function ListarDetallePed($data)
    {
        try {
            if ($data['tipo_pedido'] == 1) {
                $tabla = 'v_pedido_mesa';
            } elseif ($data['tipo_pedido'] == 2) {
                $tabla = 'v_pedido_llevar';
            } elseif ($data['tipo_pedido'] == 3) {
                $tabla = 'v_pedido_delivery';
            }
            $stm = $this->db->prepare("SELECT id_pedido FROM " . $tabla . " WHERE id_pedido = ?");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetch(PDO::FETCH_OBJ);
            /* Traemos el detalle */
            $c->{'Detalle'} = $this->db->query("SELECT id_pres,SUM(cantidad) AS cantidad, precio, estado FROM tm_detalle_pedido WHERE id_pedido = " . $c->id_pedido . " AND estado <> 'z' GROUP BY id_pres, precio")
                ->fetchAll(PDO::FETCH_OBJ);
            foreach ($c->Detalle as $k => $d) {
                $c->Detalle[$k]->{'Producto'} = $this->db->query("SELECT pro_nom, pro_pre, impuesto_icbper FROM v_productos WHERE id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function cliente_crud_create($data)
    {
        try {
            $consulta = "call usp_restRegCliente( :flag, @a, :tipo_cliente, :dni, :ruc, :nombres, :razon_social, :telefono, :fecha_nac, :correo, :direccion, :referencia);";
            $arrayParam = array(
                ':flag' => 1,
                ':tipo_cliente' => $data['tipo_cliente'],
                ':dni' => $data['dni'],
                ':ruc' => $data['ruc'],
                ':nombres' => $data['nombres'],
                ':razon_social' => $data['razon_social'],
                ':telefono' => $data['telefono'],
                ':fecha_nac' => date('Y-m-d', strtotime($data['fecha_nac'])),
                ':correo' => $data['correo'],
                ':direccion' => $data['direccion'],
                ':referencia' => $data['referencia']
            );
            $st = $this->db->prepare($consulta);
            $st->execute($arrayParam);
            $c = $st->fetch(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function cliente_crud_update($data)
    {
        try {
            $consulta = "call usp_restRegCliente( :flag, :id_cliente, :tipo_cliente, :dni, :ruc, :nombres, :razon_social, :telefono, :fecha_nac, :correo, :direccion, :referencia);";
            $arrayParam = array(
                ':flag' => 2,
                ':id_cliente' => $data['id_cliente'],
                ':tipo_cliente' => $data['tipo_cliente'],
                ':dni' => $data['dni'],
                ':ruc' => $data['ruc'],
                ':nombres' => $data['nombres'],
                ':razon_social' => $data['razon_social'],
                ':telefono' => $data['telefono'],
                ':fecha_nac' => date('Y-m-d', strtotime($data['fecha_nac'])),
                ':correo' => $data['correo'],
                ':direccion' => $data['direccion'],
                ':referencia' => $data['referencia']
            );
            $st = $this->db->prepare($consulta);
            $st->execute($arrayParam);
            $c = $st->fetch(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function buscar_cliente($token, $data)
    {
        try {


            if (!isset($data['cadena']) || empty($data['cadena'])) {
                throw new Exception("Falta el parámetro 'cadena' en los datos enviados.");
            }

            $cadena = $data['cadena'];

            $sql = "
                SELECT * 
                FROM v_clientes 
                WHERE estado <> 'i' 
                AND (
                    dni LIKE ? 
                    OR ruc LIKE ? 
                    OR nombre LIKE ?
                ) 
                LIMIT 5
            ";

            $stm = $this->db->prepare($sql);

            $searchTerm = "%" . $cadena . "%";

            // Ejecutamos la consulta con parámetros seguros
            $stm->execute([
                $searchTerm,
                $searchTerm,
                $searchTerm
            ]);

            $result = $stm->fetchAll(PDO::FETCH_OBJ);



            if (!$result) {


                if (strlen($cadena) == 8) {
                    try {

                        if (API_SERVER == "apiperu.dev") {
                            $url = 'https://apiperu.dev/api/dni/' . $cadena . '?api_token=' . $token;
                            $curl = curl_init();
                            curl_setopt_array($curl, array(
                                CURLOPT_URL => $url,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_CUSTOMREQUEST => "GET",
                                CURLOPT_SSL_VERIFYPEER => false
                            ));
                            $response = curl_exec($curl);
                            $err = curl_error($curl);
                            curl_close($curl);

                            $res = json_decode($response, true);

                        }
                        if (API_SERVER == "apiperu.net.pe") {
                            $url = 'https://apiperu.net.pe/api/dni/' . $cadena;
                            $curl = curl_init();
                            curl_setopt_array($curl, array(
                                CURLOPT_URL => $url,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_CUSTOMREQUEST => "GET",
                                CURLOPT_SSL_VERIFYPEER => false,
                                CURLOPT_HTTPHEADER => array(
                                    'Authorization: Bearer ' . $token
                                ),
                            ));
                            $response = curl_exec($curl);
                            $err = curl_error($curl);
                            curl_close($curl);

                            $res = json_decode($response, true);

                        }
                        if (API_SERVER == "server.consultaperu.xyz") {
                            $url = 'http://server.consultaperu.xyz/api/dni/' . $cadena;
                            $curl = curl_init();
                            curl_setopt_array($curl, array(
                                CURLOPT_URL => $url,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_CUSTOMREQUEST => "GET",
                                CURLOPT_SSL_VERIFYPEER => false,
                                CURLOPT_HTTPHEADER => array(
                                    'Authorization: Bearer ' . $token
                                ),
                            ));
                            $response = curl_exec($curl);
                            $err = curl_error($curl);
                            curl_close($curl);

                            $res = json_decode($response, true);

                        }
                        if ($res['success']) {

                            $data = [
                                'tipo_cliente' => 1,
                                'dni' => $res['data']['numero'] ?? '',
                                'ruc' => $res['data']['ruc'] ?? '',
                                'nombres' => $res['data']['nombres'] . ' ' . $res['data']['apellido_paterno'] . ' ' . $res['data']['apellido_materno'] ?? '',
                                'razon_social' => $res['data']['razonsocial'] ?? '',
                                'telefono' => $res['data']['telefono'] ?? 0,
                                'apellidoPaterno' => $res['data']['apellido_paterno'] ?? '',
                                'apellidoMaterno' => $res['data']['apellido_materno'] ?? '',
                                'codVerifica' => $res['data']['codigo_verificacion'] ?? '',
                                'direccion' => $res['data']['direccion_completa'] ?? '',
                                'fecha_nac' => $res['data']['fecha_nacimiento'] ?? '',
                                'correo' => $res['data']['correo'] ?? '',
                                'referencia' => $res['data']['referencia'] ?? '',
                            ];

                            $result = $this->cliente_crud_create($data);
                            if ($result) {
                                //$this->buscar_cliente($token,$data['dni']);


                                $sql1 = "
                                    SELECT * 
                                    FROM v_clientes 
                                    WHERE estado <> 'i' 
                                    AND id_cliente = ? 
                                ";

                                $stm = $this->db->prepare($sql1);

                                // Ejecutamos la consulta con parámetros seguros
                                $stm->execute([
                                    $result->id_cliente
                                ]);


                                return $stm->fetchAll(PDO::FETCH_OBJ);

                            }

                        }
                    } catch (Exception $e) {
                        die($e->getMessage());
                    }
                }

                if (strlen($cadena) == 11) {
                    try {
                        if (API_SERVER == "apiperu.dev") {
                            // $url = 'https://apiperu.net.pe/api/ruc/'.$data['cadena'].'?api_token='.$token;
                            $url = 'https://apiperu.dev/api/ruc/' . $cadena . '?api_token=' . $token;
                            $curl = curl_init();
                            curl_setopt_array($curl, array(
                                CURLOPT_URL => $url,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_CUSTOMREQUEST => "GET",
                                CURLOPT_SSL_VERIFYPEER => false
                            ));
                            $response = curl_exec($curl);
                            $err = curl_error($curl);
                            curl_close($curl);
                        }
                        if (API_SERVER == "apiperu.net.pe") {
                            // $url = 'https://apiperu.net.pe/api/ruc/'.$data['cadena'].'?api_token='.$token;
                            $url = 'https://apiperu.net.pe/api/ruc/' . $cadena;
                            $curl = curl_init();
                            curl_setopt_array($curl, array(
                                CURLOPT_URL => $url,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_CUSTOMREQUEST => "GET",
                                CURLOPT_SSL_VERIFYPEER => false,
                                CURLOPT_HTTPHEADER => array(
                                    'Authorization: Bearer ' . $token
                                ),
                            ));
                            $response = curl_exec($curl);
                            $err = curl_error($curl);
                            curl_close($curl);
                        }
                        if (API_SERVER == "server.consultaperu.xyz") {
                            $url = 'http://server.consultaperu.xyz/api/ruc/' . $cadena;
                            $curl = curl_init();
                            curl_setopt_array($curl, array(
                                CURLOPT_URL => $url,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_CUSTOMREQUEST => "GET",
                                CURLOPT_SSL_VERIFYPEER => false,
                                CURLOPT_HTTPHEADER => array(
                                    'Authorization: Bearer ' . $token
                                ),
                            ));
                            $response = curl_exec($curl);
                            $err = curl_error($curl);
                            curl_close($curl);
                        }
                        $res = json_decode($response, true);

                        if ($res['success']) {

                            $data = [
                                'tipo_cliente' => 2,
                                'dni' => $res['data']['numero'] ?? '',
                                'ruc' => $res['data']['ruc'] ?? '',
                                'nombres' => $res['data']['nombres'] ?? '',
                                'razon_social' => $res['data']['nombre_o_razon_social'] ?? '',
                                'telefono' => $res['data']['telefono'] ?? 0,
                                'apellidoPaterno' => $res['data']['apellido_paterno'] ?? '',
                                'apellidoMaterno' => $res['data']['apellido_materno'] ?? '',
                                'codVerifica' => $res['data']['codigo_verificacion'] ?? '',
                                'direccion' => $res['data']['direccion_completa'] ?? '',
                                'fecha_nac' => $res['data']['fecha_nacimiento'] ?? '',
                                'correo' => $res['data']['correo'] ?? '',
                                'referencia' => $res['data']['referencia'] ?? '',
                            ];

                            $result = $this->cliente_crud_create($data);

                            if ($result) {
                                //$this->buscar_cliente($token,$data['dni']);


                                $sql1 = "
                                    SELECT * 
                                    FROM v_clientes 
                                    WHERE estado <> 'i' 
                                    AND id_cliente = ? 
                                ";

                                $stm = $this->db->prepare($sql1);

                                // Ejecutamos la consulta con parámetros seguros
                                $stm->execute([
                                    $result->id_cliente
                                ]);


                                return $stm->fetchAll(PDO::FETCH_OBJ);

                            }

                        }
                    } catch (Exception $e) {
                        die($e->getMessage());
                    }
                }

            }

            return $result;


        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function buscar_cliente_telefono($data)
    {
        try {
            /*nota: para kerlyn quitar el tipo_cliente de la consulta*/
            $stm = $this->db->prepare("SELECT * FROM v_clientes WHERE estado <> 'i' AND (dni LIKE '%" . $data['cadena'] . "%' OR ruc LIKE '%" . $data['cadena'] . "%' OR nombre LIKE '%" . $data['cadena'] . "%' OR telefono LIKE '%" . $data['cadena'] . "%') ORDER BY dni LIMIT 5");
            $stm->execute();
            return $stm->fetchAll(PDO::FETCH_OBJ);
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    /*
    public function buscar_cliente_telefono($data)
    {
        try
        {   


            $stm = $this->db->prepare("SELECT p.id_pedido, pd.telefono_cliente, pd.nombre_cliente, pd.direccion_cliente, pd.referencia_cliente FROM tm_pedido_delivery AS pd INNER JOIN tm_pedido AS p ON pd.id_pedido = p.id_pedido WHERE pd.telefono_cliente LIKE '%".$data['cadena']."%' AND pd.id_pedido = (SELECT MAX(id_pedido) FROM tm_pedido_delivery WHERE telefono_cliente LIKE '%".$data['cadena']."%') GROUP BY pd.telefono_cliente LIMIT 5");
            $stm->execute();
            return $stm->fetchAll(PDO::FETCH_OBJ); 
        }
        catch(Exception $e)
        {
            die($e->getMessage());
        }
    }
    */

    public function tags_list($data)
    {
        try {
            $stm = $this->db->prepare("SELECT p.id_prod,p.notas FROM tm_producto AS p INNER JOIN tm_producto_pres AS pp ON p.id_prod = pp.id_prod WHERE pp.id_pres = ?");
            $stm->execute(array($data['id_pres']));
            return $stm->fetch(PDO::FETCH_OBJ);
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function tags_crud($data)
    {
        try {
            // 1. Obtener nota actual del producto
            $sql = "SELECT notas FROM tm_producto WHERE id_prod = ?";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$data['id_prod']]);
            $result = $stmt->fetch();

            $notasActuales = isset($result['notas']) ? $result['notas'] : '';

            // 2. Convertir a array y limpiar duplicados
            $arrayNotas = array_filter(array_map('trim', explode(',', $notasActuales)));
            $nuevaNota = trim($data['notas']); // usamos 'nota' singular para nueva nota

            // 3. Evitar duplicados
            if (!in_array(strtoupper($nuevaNota), array_map('strtoupper', $arrayNotas))) {
                $arrayNotas[] = $nuevaNota;
            }

            // 4. Reconstruir el string de notas
            $notasActualizadas = implode(', ', $arrayNotas);

            // 5. Actualizar base de datos
            $sqlUpdate = "UPDATE tm_producto SET notas = ? WHERE id_prod = ?";
            $this->db->prepare($sqlUpdate)->execute([$notasActualizadas, $data['id_prod']]);

            return [
                'success' => true,
                'message' => 'Nota actualizada correctamente.',
                'notas' => $notasActualizadas
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => 'Error al actualizar nota.',
                'error' => $e->getMessage()
            ];
        }
    }


    public function RegistrarVenta($data)
    {
        try {
            // 1. Configuración de fecha y zona horaria
            date_default_timezone_set($_SESSION["zona_horaria"]);
            setlocale(LC_ALL, "es_ES@euro", "es_ES", "esp");
            $fecha = date("Y-m-d H:i:s");

            // 2. Validación de detalles y total
            $conteo = $this->db
                ->query("SELECT COUNT(*) AS conteo FROM tm_detalle_pedido WHERE id_pedido = " . (int) $data['id_pedido'])
                ->fetch(PDO::FETCH_OBJ);

            // Log para depurar
            error_log("RegistrarVenta: detalle count = {$conteo->conteo}, total = {$data['total']}");

            if ($conteo->conteo <= 0) {
                throw new Exception("Validación fallida: no hay detalles (conteo=0) para id_pedido={$data['id_pedido']}.");
            }
            if ($data['total'] <= 0) {
                throw new Exception("Validación fallida: total inválido ({$data['total']}).");
            }

            // 3. Verificar existencia de apertura de caja (clave foránea)
            $apcId = (int) Session::get('apcid');
            $existeApertura = $this->db
                ->query("SELECT 1 FROM tm_aper_cierre WHERE id_apc = {$apcId}")
                ->fetchColumn();
            if (!$existeApertura) {
                throw new Exception("No existe tm_aper_cierre.id_apc = {$apcId}");
            }

            // 4. Preparar llamada al procedimiento y habilitar excepciones PDO
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $sql = "
            CALL usp_restEmitirVenta(
                :flag,
                :dividir_cuenta,
                :id_pedido,
                :tipo_pedido,
                :tipo_entrega,
                :id_cliente,
                :id_tipo_doc,
                :id_tipo_pago,
                :id_usu,
                :id_apc,
                :pago_efe_none,
                :pago_tar,
                :pago_yape,
                :pago_plin,
                :pago_tran,
                :descuento_tipo,
                :descuento_personal,
                :descuento_monto,
                :descuento_motivo,
                :comision_tarjeta,
                :comision_delivery,
                :igv,
                :total,
                :codigo_operacion,
                :fecha_venta
            );
        ";
            $params = [
                ':flag' => 1,
                ':dividir_cuenta' => $data['dividir_cuenta'],
                ':id_pedido' => $data['id_pedido'],
                ':tipo_pedido' => $data['tipo_pedido'],
                ':tipo_entrega' => $data['tipo_entrega'] ?? null,
                ':id_cliente' => $data['cliente_id'],
                ':id_tipo_doc' => $data['tipo_doc'],
                ':id_tipo_pago' => $data['tipo_pago'],
                ':id_usu' => Session::get('usuid'),
                ':id_apc' => $apcId,
                ':pago_efe_none' => $data['pago_efe'],
                ':pago_tar' => $data['pago_tar'],
                ':pago_yape' => $data['pago_yape'] ?? 0,
                ':pago_plin' => $data['pago_plin'] ?? 0,
                ':pago_tran' => $data['pago_tran'] ?? 0,
                ':descuento_tipo' => $data['descuento_tipo'],
                ':descuento_personal' => $data['descuento_personal'],
                ':descuento_monto' => $data['descuento_monto'],
                ':descuento_motivo' => $data['descuento_motivo'],
                ':comision_tarjeta' => $data['comision_tarjeta'],
                ':comision_delivery' => $data['comision_delivery'],
                ':igv' => Session::get('igv'),
                ':total' => $data['total'],
                ':codigo_operacion' => $data['codigo_operacion'],
                ':fecha_venta' => $fecha
            ];

            $st = $this->db->prepare($sql);
            try {
                error_log("usp_restEmitirVenta params: " . json_encode($params));
                $st->execute($params);
            } catch (PDOException $e) {
                $info = $st->errorInfo();
                error_log("SQLSTATE={$info[0]}, Code={$info[1]}, Msg={$info[2]}");
                error_log($st->debugDumpParams());
                throw new Exception(
                    "Error en usp_restEmitirVenta (SQLSTATE={$info[0]}, Code={$info[1]}): {$info[2]}"
                );
            }

            // 5. Obtener nuevo id_venta
            $id_venta = null;
            while ($row = $st->fetch(PDO::FETCH_ASSOC)) {
                $id_venta = $row['id_venta'];
            }
            if (!$id_venta) {
                throw new Exception("El procedimiento no devolvió 'id_venta'.");
            }



            // 6. Actualizar consumo/observación
            $dbConsumo = new Database(DB_TYPE, DB_HOST, DB_NAME, DB_USER, DB_PASS, DB_CHARSET);
            $dbConsumo->prepare(
                "UPDATE tm_venta 
                SET consumo = ?, 
                    consumo_desc = ?, 
                    observacion = ? 
              WHERE id_venta = ?"
            )->execute([
                        $data['venta_por_consumo'],
                        $data['venta_por_consumo_concepto'],
                        $data['observacion'],
                        $id_venta
                    ]);

            // 7. Insertar detalles de venta
            $dbDetalle = new Database(DB_TYPE, DB_HOST, DB_NAME, DB_USER, DB_PASS, DB_CHARSET);
            $ids = $data['idProd'];
            $cants = $data['cantProd'];
            $pres = $data['precProd'];
            for ($i = 0; $i < count($ids); ++$i) {
                if ((int) $cants[$i] > 0) {
                    $dbDetalle->prepare(
                        "INSERT INTO tm_detalle_venta 
                        (id_venta, id_prod, cantidad, precio) 
                     VALUES (?, ?, ?, ?)"
                    )->execute([
                                $id_venta,
                                $ids[$i],
                                $cants[$i],
                                $pres[$i]
                            ]);
                }
            }

            // 8. Llamar segundo SP para vincular detalles
            $this->db = new Database(DB_TYPE, DB_HOST, DB_NAME, DB_USER, DB_PASS, DB_CHARSET);
            $stm = $this->db->prepare("
            CALL usp_restEmitirVentaDet(:flag, :id_venta, :id_pedido, :fecha);
        ");
            $stm->execute([
                ':flag' => 1,
                ':id_venta' => $id_venta,
                ':id_pedido' => $data['id_pedido'],
                ':fecha' => $fecha
            ]);



            return $id_venta;

        } catch (Exception $e) {
            // Aquí ya verás mensajes claros de por qué falló
            die($e->getMessage());
        }
    }


    private function updateStockProduct(array $ids, array $cantidades): array
    {
        if (count($ids) !== count($cantidades)) {
            throw new \InvalidArgumentException(
                'Los arrays $ids y $cantidades deben tener igual longitud.'
            );
        }

        // Modo excepciones
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        // Preparar consultas
        $stmtProd = $this->db->prepare("
        SELECT receta, crt_stock, stock
          FROM tm_producto_pres
         WHERE id_pres = :id
         AND estado = 'a'
    ");

        $stmtIngr = $this->db->prepare("
        SELECT id_ins, cant
          FROM tm_producto_ingr
         WHERE id_pres = :id
    ");
        $stmtUpdPres = $this->db->prepare("
        UPDATE tm_producto_pres
           SET stock = stock - :cantidad
         WHERE id_pres = :id
    ");
        $stmtUpdInsumo = $this->db->prepare("
        UPDATE tm_insumo
           SET stock = stock - :cantidad
         WHERE id_ins = :idIns
    ");

        $results = [
            'updates_pres' => [],
            'updates_ins' => [],
        ];

        try {
            foreach ($ids as $i => $rawId) {
                $idProd = (int) $rawId;
                $cantProd = (float) $cantidades[$i];

                // 1) Leer receta y control de stock
                $stmtProd->execute([':id' => $idProd]);
                $row = $stmtProd->fetch(PDO::FETCH_ASSOC);
                if (!$row) {
                    throw new \RuntimeException("Producto id_pres={$idProd} no existe.");
                }
                $receta = (int) $row['receta'];
                $crtStock = (int) $row['crt_stock'];


                // 3) Si lleva control y tiene receta, actualizar insumos
                if ($receta === 1 && $crtStock === 1) {
                    $stmtIngr->execute([':id' => $idProd]);
                    $insumos = $stmtIngr->fetchAll(PDO::FETCH_ASSOC);

                    $results['updates_ins'][$idProd] = [];
                    foreach ($insumos as $ing) {
                        $idIns = (int) $ing['id_ins'];
                        $cantIngr = (float) $ing['cant'];
                        // calcular cantidad a sumar: cantIngr * cantProd
                        $toAdd = $cantIngr * $cantProd;

                        $stmtUpdInsumo->execute([
                            ':cantidad' => $toAdd,
                            ':idIns' => $idIns,
                        ]);
                        $results['updates_ins'][$idProd][$idIns]
                            = $stmtUpdInsumo->rowCount();

                    }

                } else if ($receta === 0 && $crtStock === 1) {

                    $stmtUpdPres->execute([
                        ':cantidad' => $cantProd,
                        ':id' => $idProd,
                    ]);
                    $results['updates_pres'][$idProd] = $stmtUpdPres->rowCount();

                }


            }

            return $results;

        } catch (\PDOException $e) {
            throw new \RuntimeException(
                "Error al actualizar stock e insumos: " . $e->getMessage(),
                0,
                $e
            );
        }
    }

    private function detalleKardex(array $ids, array $cantidades, string $tipoOperacion): void
    {

        if (count($ids) !== count($cantidades)) {
            throw new \InvalidArgumentException(
                'Los arrays $ids y $cantidades deben tener igual longitud.'
            );
        }

        // Modo excepciones
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $tipoKardex = ($tipoOperacion === 'ingreso') ? 5 : 4;
        $concepto = ($tipoOperacion === 'ingreso') ? "ingreso por anulacion de pedido" : "salida por pedido";

        // Preparar consultas
        $stmtProd = $this->db->prepare("
            SELECT precio, receta, crt_stock, stock
            FROM tm_producto_pres
            WHERE id_pres = :id
            AND estado = 'a'
        ");

        $stmtIngr = $this->db->prepare("
            SELECT pi.id_ins, pi.cant, i.cos_uni, i.stock
            FROM tm_producto_ingr pi
            INNER JOIN tm_insumo i ON i.id_ins = pi.id_ins 
            WHERE pi.id_pres = :id
        ");



        try {

            $serie_doc = null;
            $nro_doc = null;
            $tipo_doc = null;



            foreach ($ids as $i => $rawId) {
                $idProd = (int) $rawId;
                $cantProd = (float) $cantidades[$i];

                // 1) Leer receta y control de stock
                $stmtProd->execute([':id' => $idProd]);
                $row = $stmtProd->fetch(PDO::FETCH_ASSOC);
                if (!$row) {
                    throw new \RuntimeException("Producto id_pres={$idProd} no existe.");
                }
                $receta = (int) $row['receta'];
                $crtStock = (int) $row['crt_stock'];
                $precio = (float) $row['precio'];
                $stock = (float) $row['stock'];



                // 3) Si lleva control y tiene receta, actualizar insumos
                if ($receta === 1 || $crtStock === 1) {
                    if ($receta === 1 && $crtStock === 1) {
                        $stmtIngr->execute([':id' => $idProd]);
                        $insumos = $stmtIngr->fetchAll(PDO::FETCH_ASSOC);


                        foreach ($insumos as $ing) {
                            $idIns = (int) $ing['id_ins'];
                            $cantIngr = (float) $ing['cant'];
                            $precioIngr = (float) $ing['cos_uni'];
                            $stockIngr = (float) $ing['stock'];
                            // calcular cantidad a sumar: cantIngr * cantProd
                            $toAdd = $cantIngr * $cantProd;

                            $dataKardex = array(
                                'tipo_kardex' => $tipoKardex,
                                'presentacion_id' => $idIns,
                                'tipo_presentacion' => 2,
                                'cantidad' => $toAdd,
                                'costo_unitario' => $precioIngr,
                                'serie_documento' => $serie_doc,
                                'numero_documento' => $nro_doc,
                                'tipo_documento' => $tipo_doc,
                                'concepto' => $concepto,
                                'stock' => $stockIngr,
                                'estado' => 'activo'
                            );

                        }



                    } else if ($receta === 0 && $crtStock === 1) {


                        $dataKardex = array(
                            'tipo_kardex' => $tipoKardex, // 4 ventas
                            'presentacion_id' => $idProd,
                            'tipo_presentacion' => 1,
                            'cantidad' => $cantProd,
                            'costo_unitario' => $precio,
                            'serie_documento' => $serie_doc,
                            'numero_documento' => $nro_doc,
                            'tipo_documento' => $tipo_doc,
                            'concepto' => $concepto,
                            'stock' => $stock,
                            'estado' => 'activo'
                        );


                    }

                    $this->registrarKardex($dataKardex);
                }

            }


        } catch (\PDOException $e) {
            throw new \RuntimeException(
                "Error al actualizar stock e insumos: " . $e->getMessage(),
                0,
                $e
            );
        }
    }


    public function registrarKardex(array $data): array
    {
        $this->db->beginTransaction();

        // 2.2 Construyes el payload para kardex
        $payloadKardex = [
            'id_usuario' => Session::get('usuid'),
            'tipo_kardex' => $data['tipo_kardex'],
            'tipo_envio_sunat' => 'prueba',
            'id_presentacion' => (int) $data['presentacion_id'],
            'tipo_presentacion' => (int) $data['tipo_presentacion'],
            'cantidad_entrada' => $data['tipo_kardex'] == 5 ? $data['cantidad'] : 0,
            'cantidad_salida' => $data['tipo_kardex'] == 4 ? $data['cantidad'] : 0,
            'costo_unitario' => $data['costo_unitario'],
            'costo_total' => (float) $data['costo_unitario'] * (float) $data['cantidad'],
            'concepto' => $data['concepto'] ?? '',
            'serie_documento' => $data['serie_documento'] ?? null,
            'numero_documento' => $data['numero_documento'] ?? null,
            'tipo_documento' => $data['tipo_documento'] ?? null,
            'stock' => $data['stock'] ?? '0',
            'estado' => 'activo',
        ];

        $kardex = new Kardex(); // comparte el mismo PDO
        $out = $kardex->insert($payloadKardex);
        if (!$out['ok']) {
            $this->db->rollBack();
            return $out; // envelope con error (VALIDATION_ERROR / DB_ERROR, etc.)
        }
        $this->db->commit();

        return ['ok' => true];
    }


    public function anular_pedido($data)
    {
        try {
            if ($data['tipo_pedido'] == 1) {

                $consulta = "call usp_restDesocuparMesa( :flag, :id_pedido);";
                $arrayParam = array(
                    ':flag' => 1,
                    ':id_pedido' => $data['id_pedido']
                );
                $st = $this->db->prepare($consulta);
                $st->execute($arrayParam);

            } elseif ($data['tipo_pedido'] == 2 or $data['tipo_pedido'] == 3) {

                $sql = "UPDATE tm_pedido SET estado = 'z' WHERE id_pedido = ?";
                $this->db->prepare($sql)->execute(array($data['id_pedido']));

            }
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function anular_venta($data)
    {
        try {
            $sql1 = "UPDATE tm_inventario SET estado = 'i' WHERE id_tipo_ope = 2 AND id_ope = ?";
            $this->db->prepare($sql1)->execute(array($data['id_venta']));
            $sql2 = "UPDATE tm_venta SET estado = 'i' WHERE id_venta = ?";
            $this->db->prepare($sql2)->execute(array($data['id_venta']));
            $sql3 = "UPDATE tm_pedido SET estado = 'z' WHERE id_pedido = ?";
            $this->db->prepare($sql3)->execute(array($data['id_pedido']));
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function pedido_edit($data)
    {
        try {
            $stm = $this->db->prepare("SELECT * FROM tm_pedido_delivery WHERE id_pedido = ?");
            $stm->execute(array($data['id_pedido']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function pedido_delete($data)
    {
        try {


            // 2. Obtener información del producto antes de cancelar (opcional)
            $stm = $this->db->prepare("
            SELECT 
                p.pro_nom AS producto, 
                p.pro_pre AS presentacion, 
                d.cant AS cantidad, 
                d.precio, 
                d.comentario, 
                i.nombre AS nombre_imp 
            FROM tm_detalle_pedido AS d 
            INNER JOIN v_productos AS p ON d.id_pres = p.id_pres 
            INNER JOIN tm_area_prod AS a ON a.id_areap = p.id_areap 
            INNER JOIN tm_impresora AS i ON i.id_imp = a.id_imp 
            WHERE d.id_pedido = ? 
              AND d.id_pres = ? 
              AND d.estado <> 'z' 
              AND d.cant > 0 
            GROUP BY d.id_pres 
            ORDER BY d.fecha_pedido DESC
        ");
            $stm->execute([(int) $data['id_pedido'], (int) $data['id_pres']]);
            $data_producto = $stm->fetchAll(PDO::FETCH_OBJ);

            // 3. Ejecutar procedimiento de cancelación
            $filtro_seguridad = Session::get('cod_seg');

            $fecha_envio = date("Y-m-d H:i:s");

            $consulta = "CALL usp_restCancelarPedido(
            :flag, :id_usu, :id_pres, :id_pedido, 
            :estado_pedido, :fecha_pedido, :fecha_envio, 
            :codigo_seguridad, :filtro_seguridad
        );";

            $arrayParam = [
                ':flag' => 1,
                ':id_usu' => Session::get('usuid'),
                ':id_pres' => (int) $data['id_pres'],
                ':id_pedido' => (int) $data['id_pedido'],
                ':estado_pedido' => $data['estado_pedido'],
                ':fecha_pedido' => $data['fecha_pedido'],
                ':fecha_envio' => $fecha_envio,
                ':codigo_seguridad' => $data['codigo_seguridad'],
                ':filtro_seguridad' => $filtro_seguridad
            ];

            // Depuración de parámetros

            $st = $this->db->prepare($consulta);
            $st->execute($arrayParam);
            $codigo_respuesta = $st->fetchAll(PDO::FETCH_OBJ);

            // 🧠 IMPORTANTE: liberar todos los resultsets restantes
            while ($st->nextRowset()) {
            }


            if (!empty($codigo_respuesta) && isset($codigo_respuesta[0]->cod) && $codigo_respuesta[0]->cod == 1 && $data['estado_pedido'] !== "c") {

                // Volver a consultar el detalle luego del CALL
                $stm_detalle = $this->db->prepare("
                SELECT id_pres, cant, estado, fecha_pedido
                FROM tm_detalle_pedido
                WHERE id_pedido = ? AND id_pres = ?
                ORDER BY fecha_pedido DESC
            ");
                $stm_detalle->execute([(int) $data['id_pedido'], (int) $data['id_pres']]);
                $detalle = $stm_detalle->fetch(PDO::FETCH_OBJ);
                //$debug[] = "Registros post-CALL: " . json_encode($detalle);

                if (!$detalle || empty($detalle->id_pres)) {
                    $debug[] = "Error: detalle vacío o id_pres inválido. Valor actual: " . var_export($detalle, true);
                } else {
                    $debug[] = "OK: id_pres a consultar = " . $detalle->id_pres;
                }

                if ($detalle) {
                    $debug[] = "Detalle encontrado: " . json_encode($detalle);
                    $debug[] = "Valor exacto de id_pres (con var_export): " . var_export($detalle->id_pres, true);

                    // Buscar configuración en tm_producto_pres
                    // $stm_pres = $this->db->prepare("
                    //     SELECT receta, crt_stock 
                    //     FROM tm_producto_pres 
                    //     WHERE id_pres = ?
                    //     LIMIT 1
                    // ");


                    // $stm_pres->execute([(int) $detalle->id_pres]);
                    // $presentacion = $stm_pres->fetch(PDO::FETCH_OBJ);
                    // $debug[] = "Presentación encontrada: " . json_encode($presentacion);

                    // Verificación directa (por si acaso)
                    $stm_pres_test = $this->db->prepare("SELECT * FROM tm_producto_pres WHERE id_pres = ?");
                    $stm_pres_test->execute([(int) $data['id_pres']]);
                    $verif = $stm_pres_test->fetch(PDO::FETCH_OBJ);
                    $debug[] = "Verificación directa de tm_producto_pres: " . json_encode($verif);

                    $res = $this->restablecerInventario($this->db, $detalle->id_pres, $detalle->cant);

                    $ids = [(int) $detalle->id_pres];
                    $cantidades = [(float) $detalle->cant];

                    if ($res) {

                        $this->detalleKardex($ids, $cantidades, "ingreso", 1);

                    }

                    if (!$res) {
                        $debug[] = "error en reponer stock {$res}";
                    }

                    $debug[] = "Repuesto producto ID {$detalle->id_pres}, cantidad {$detalle->cant}";


                } else {
                    $debug[] = "No se encontró detalle cancelado para reponer.";
                }
            }

            echo json_encode([
                "Producto" => $data_producto,
                "Codigo" => $codigo_respuesta,
                //"Debug" => $debug
            ]);

        } catch (Exception $e) {
            error_log("Error en pedido_delete: " . $e->getMessage());
            die($e->getMessage());
        }
    }





    // public function restablecerInventario($db, $id_ins, $cantidadADevolver)
    // {
    //     try {

    //         $stmt = $db->prepare("SELECT stock FROM tm_producto_pres 
    //         WHERE id_pres = ? AND estado = 'a'");
    //         $stmt->execute([$id_ins]);
    //         $inv = $stmt->fetch(PDO::FETCH_OBJ);

    //         if ($inv) {
    //             $nuevaCant = $inv->stock + $cantidadADevolver;
    //             $stmtUpd = $db->prepare("UPDATE tm_producto_pres SET stock = ? WHERE id_pres = ?");
    //             $stmtUpd->execute([$nuevaCant, $id_ins]);
    //             error_log("Stock actualizado: id_ins={$id_ins}, nuevo_cant=$nuevaCant");
    //             return true;
    //         }

    //         error_log("No se encontró inventario activo para id_ins=$id_ins");
    //         return false;
    //     } catch (Exception $e) {
    //         error_log("Error en restablecerInventario: " . $e->getMessage());
    //         return false;
    //     }
    // }

    public function restablecerInventario(PDO $db, int $id_pres, float $cantidadADevolver): bool
    {
        // 0) Validación rápida
        if ($cantidadADevolver <= 0) {
            error_log("Cantidad a devolver inválida: $cantidadADevolver");
            return false;
        }

        // Normaliza a 3 decimales (string con punto)
        $deltaPres = sprintf('%.3f', $cantidadADevolver);

        // 1) Manejo de transacción seguro (evita anidar)
        $startedTx = !$db->inTransaction();
        if ($startedTx) {
            $db->beginTransaction();
        }

        try {
            // 2) Traer flags de la presentación
            $stmPres = $db->prepare("
            SELECT receta, crt_stock
            FROM tm_producto_pres
            WHERE id_pres = :id
            LIMIT 1
        ");
            $stmPres->execute([':id' => $id_pres]);
            $presentacion = $stmPres->fetch(PDO::FETCH_ASSOC);

            if (!$presentacion) {
                error_log("Presentación no encontrada: id_pres={$id_pres}");
                if ($startedTx)
                    $db->rollBack();
                return false;
            }

            $receta = (int) $presentacion['receta'];    // 1 = usa insumos
            $crtStock = (int) $presentacion['crt_stock']; // 1 = controla stock

            if ($crtStock !== 1) {
                // No controla stock: no hay nada que reponer
                if ($startedTx)
                    $db->commit();
                return true;
            }

            if ($receta === 1) {
                // 3) Reponer INSUMOS según receta (BOM)
                $stmtIngr = $db->prepare("
                SELECT pi.id_ins, pi.cant
                FROM tm_producto_ingr pi
                WHERE pi.id_pres = :id
            ");
                $stmtIngr->execute([':id' => $id_pres]);
                $insumos = $stmtIngr->fetchAll(PDO::FETCH_ASSOC);

                if (!$insumos) {
                    error_log("Presentación con receta pero sin insumos: id_pres={$id_pres}");
                    if ($startedTx)
                        $db->rollBack();
                    return false;
                }

                $updIns = $db->prepare("
                UPDATE tm_insumo
                   SET stock = stock + CAST(:delta AS DECIMAL(12,3))
                 WHERE id_ins = :id_ins
                 LIMIT 1
            ");

                foreach ($insumos as $ing) {
                    $idIns = (int) $ing['id_ins'];
                    $cantIngr = (float) $ing['cant'];

                    // cantidad a sumar = cantIngr * cantidadADevolver (3 decimales)
                    // Si tienes BCMath, sería mejor bc*; si no, formatea:
                    $toAdd = sprintf('%.3f', $cantIngr * (float) $deltaPres);

                    $ok = $updIns->execute([
                        ':delta' => $toAdd,
                        ':id_ins' => $idIns,
                    ]);

                    if (!$ok || $updIns->rowCount() === 0) {
                        error_log("No se actualizó stock insumo id_ins={$idIns}");
                        if ($startedTx)
                            $db->rollBack();
                        return false;
                    }

                    error_log("Stock insumo incrementado: id_ins={$idIns}, +{$toAdd}");
                }

                if ($startedTx)
                    $db->commit();
                return true;

            } else {
                // 4) Reponer PRESENTACIÓN (producto final)
                $updPres = $db->prepare("
                UPDATE tm_producto_pres
                   SET stock = stock + CAST(:delta AS DECIMAL(12,3))
                 WHERE id_pres = :id_pres
                   AND estado = 'a'
                 LIMIT 1
            ");

                $ok = $updPres->execute([
                    ':delta' => $deltaPres,
                    ':id_pres' => $id_pres,
                ]);

                if (!$ok || $updPres->rowCount() === 0) {
                    error_log("No se actualizó stock (id_pres={$id_pres}). ¿Existe y está activo?");
                    if ($startedTx)
                        $db->rollBack();
                    return false;
                }

                error_log("Stock incrementado: id_pres={$id_pres}, +{$deltaPres}");
                if ($startedTx)
                    $db->commit();
                return true;
            }

        } catch (Throwable $e) {
            if ($startedTx && $db->inTransaction()) {
                $db->rollBack();
            }
            error_log("Error en restablecerInventario: " . $e->getMessage());
            return false;
        }
    }



    public function pedido_crud_update($data)
    {
        try {
            $sql = "UPDATE tm_pedido_delivery SET id_repartidor = ?, hora_entrega = ?, amortizacion = ?, tipo_pago = ?, paga_con = ?, comision_delivery = ? WHERE id_pedido = ?";
            $this->db->prepare($sql)->execute(array(
                $data['id_repartidor'],
                $data['hora_entrega'],
                $data['amortizacion'],
                $data['tipo_pago'],
                $data['paga_con'],
                $data['comision_delivery'],
                $data['id_pedido']
            ));
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function venta_edit($data)
    {
        try {
            $stm = $this->db->prepare("SELECT id_tipo_pago,id_pedido,id_venta FROM tm_venta WHERE id_venta = ?");
            $stm->execute(array($data['id_venta']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function venta_edit_pago($data)
    {
        try {
            if ($data['tipo_pago'] <> $data['id_tipo_pago']) {
                if ($data['tipo_pago'] == 1) {
                    $sql = "UPDATE tm_venta SET id_tipo_pago = ?, pago_tar = pago_efe, pago_efe = '0.00' WHERE id_venta = ?";
                    $this->db->prepare($sql)->execute(array($data['id_tipo_pago'], $data['id_venta']));
                } else {

                    if ($data['id_tipo_pago'] == 1) {
                        $sql = "UPDATE tm_venta SET id_tipo_pago = ?, pago_efe = pago_tar, pago_tar = '0.00' WHERE id_venta = ?";
                        $this->db->prepare($sql)->execute(array($data['id_tipo_pago'], $data['id_venta']));
                    } else {
                        $sql = "UPDATE tm_venta SET id_tipo_pago = ? WHERE id_venta = ?";
                        $this->db->prepare($sql)->execute(array($data['id_tipo_pago'], $data['id_venta']));
                    }
                }
            }
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function venta_edit_documento($data)
    {
        try {

            $consulta = "call usp_restEditarVentaDocumento( :flag, :id_venta, :id_cliente, :id_tipo_documento);";
            $arrayParam = array(
                ':flag' => 1,
                ':id_venta' => $data['id_venta'],
                ':id_cliente' => $data['id_cliente'],
                ':id_tipo_documento' => $data['id_tipo_documento']
            );
            $st = $this->db->prepare($consulta);
            $st->execute($arrayParam);
            $row = $st->fetch(PDO::FETCH_ASSOC);

            // insertar datos extras al convertir NV a CPE
            $this->db_edit = new Database(DB_TYPE, DB_HOST, DB_NAME, DB_USER, DB_PASS, DB_CHARSET);
            $sqledit = "UPDATE tm_venta SET fecha_venta = ?, nvoriginal = ?, nvfecha = ?  WHERE id_venta = ? ";
            $this->db_edit->prepare($sqledit)->execute(array(date('Y-m-d H:i:s', strtotime($data['fecha_nueva'])), $data['nv_original'], date('Y-m-d', strtotime($data['nv_fecha'])), $data['id_venta']));

            return $row;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    /* INICIO COMPROBANTE SIN ENVIAR SUNAT */

    public function contadorSunatSinEnviar()
    {
        try {


            $ds = $this->db->prepare("SELECT bloqueo FROM tm_configuracion");
            $ds->execute();
            $data_s = $ds->fetch();

            if (Session::get('rol') == 1) {
                Session::set('bloqueo', '0');
                Session::set('bloqueo_id', $data_s['bloqueo']);
                $status = '';
            } else {
                Session::set('bloqueo', $data_s['bloqueo']);
                Session::set('bloqueo_id', $data_s['bloqueo']);
                $status = 'bloqueo';
            }




            $stm = $this->db->prepare("SELECT COUNT(v.id_ven) AS total FROM v_ventas_con AS v INNER JOIN v_caja_aper AS c ON v.id_apc = c.id_apc INNER JOIN tm_tipo_doc AS d ON v.id_tdoc = d.id_tipo_doc WHERE v.ser_doc = d.serie AND v.id_tdoc <> 3 AND v.estado = 'a' AND (v.enviado_sunat = '' OR v.enviado_sunat = '0' OR v.enviado_sunat IS NULL)");
            $stm->execute();
            $c = $stm->fetch(PDO::FETCH_OBJ);

            if ($data_s['bloqueo'] == 0) {
                $c->{'status'} = '';
            } else {
                $c->{'status'} = $status;
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    /* FIN COMPROBANTE SIN ENVIAR SUNAT */

    /* INICIO PEDIDOS PREPARADOS */

    public function contadorPedidosPreparados()
    {
        try {
            if (Session::get('rol') == 1 or Session::get('rol') == 2 or Session::get('rol') == 3) {
                $stm = $this->db->prepare("SELECT COUNT(id_pedido) AS cantidad FROM v_cocina_me WHERE id_tipo = 1 AND cantidad > 0 AND estado = 'c'");
                $stm->execute();
            } elseif (Session::get('rol') == 5) {
                $stm = $this->db->prepare("SELECT COUNT(id_pedido) AS cantidad FROM v_cocina_me WHERE id_tipo = 1 AND id_mozo = ? AND cantidad > 0 AND estado = 'c'");
                $stm->execute(array(Session::get('usuid')));
            }
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function listarPedidosPreparados()
    {
        try {
            if (Session::get('rol') == 1 or Session::get('rol') == 2 or Session::get('rol') == 3) {
                $stm = $this->db->prepare("SELECT * FROM v_cocina_me WHERE id_tipo = 1 AND cantidad > 0 AND estado = 'c'");
                $stm->execute();
            } elseif (Session::get('rol') == 5) {
                $stm = $this->db->prepare("SELECT * FROM v_cocina_me WHERE id_tipo = 1 AND id_mozo = ? AND cantidad > 0 AND estado = 'c'");
                $stm->execute(array(Session::get('usuid')));
            }
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function pedidoEntregado($data)
    {
        try {
            $sql = "UPDATE tm_detalle_pedido SET estado = 'd' WHERE id_pedido = ? AND id_pres = ? AND fecha_pedido = ?";
            $this->db->prepare($sql)
                ->execute(array(
                    $data['id_pedido'],
                    $data['id_pres'],
                    $data['fecha_pedido']
                ));
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function pedido_estado_update($data)
    {
        try {

            if ($data['estado'] == 'i') {
                $estado = 'p';
            }
            ;

            if ($data['estado'] == 'i') {
                $sql = "UPDATE tm_mesa SET estado = ? WHERE id_mesa = ?";
                $this->db->prepare($sql)->execute(array($estado, $data['id_mesa']));
            }


        } catch (Exception $e) {
            return false;
        }
    }

    /* FIN PEDIDOS PREPARADOS */
    public function menu_categoria_list()
    {
        try {
            $stm = $this->db->prepare("SELECT * FROM tm_producto_catg WHERE delivery = 1");
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function menu_plato_list($data)
    {
        try {
            $stm = $this->db->prepare("SELECT * FROM v_productos WHERE del_a = 1 AND del_b = 1 AND del_c = 1 AND id_catg = ?");
            $stm->execute(array($data['id_catg']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function menu_plato_estado($data)
    {
        try {
            if ($data['estado'] == 'a') {
                $estado = 'i';
            } elseif ($data['estado'] == 'i') {
                $estado = 'a';
            }
            ;
            $sql = "UPDATE tm_producto_pres SET estado = ? WHERE id_pres = ?";
            $this->db->prepare($sql)->execute(array($estado, $data['id_pres']));
        } catch (Exception $e) {
            return false;
        }
    }

    /* INICIO IMPRESION */

    public function impresion_precuenta($id_pedido)
    {
        try {
            $stm = $this->db->prepare("SELECT * FROM v_pedido_mesa WHERE id_pedido = ?");
            $stm->execute(array($id_pedido));
            $c = $stm->fetch(PDO::FETCH_OBJ);
            /* Traemos el detalle */
            $c->{'Detalle'} = $this->db->query("SELECT id_pres,SUM(cantidad) AS cantidad, precio FROM tm_detalle_pedido WHERE id_pedido = " . $c->id_pedido . " AND estado <> 'z' GROUP BY id_pres, precio")
                ->fetchAll(PDO::FETCH_OBJ);
            foreach ($c->Detalle as $k => $d) {
                $c->Detalle[$k]->{'Producto'} = $this->db->query("SELECT pro_nom, pro_pre FROM v_productos WHERE id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }
            $c->{'host_pc'} = Session::get('host_pc');
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function impresion_reparto($id_venta)
    {
        try {
            $stm = $this->db->prepare("SELECT v.id_ven, v.id_ped, v.id_cli, v.desc_tp, v.id_tpag, v.fec_ven, v.pago_efe, v.pago_efe_none, v.pago_tar,IFNULL((v.total+v.comis_del-v.desc_monto),0) AS total, d.nro_pedido FROM v_ventas_con AS v INNER JOIN tm_pedido_delivery AS d ON v.id_ped = d.id_pedido WHERE id_ven = ?");
            $stm->execute(array($id_venta));
            $c = $stm->fetch(PDO::FETCH_OBJ);
            $c->{'Cliente'} = $this->db->query("SELECT * FROM v_clientes WHERE id_cliente = " . $c->id_cli)->fetch(PDO::FETCH_OBJ);
            $c->{'Config'} = $this->db->query("SELECT pedido_comanda FROM tm_configuracion WHERE id_cfg = 1")->fetch(PDO::FETCH_OBJ);
            /* Traemos el detalle */
            $c->{'Detalle'} = $this->db->query("SELECT id_prod,SUM(cantidad) AS cantidad, precio FROM tm_detalle_venta WHERE id_venta = " . $c->id_ven . " GROUP BY id_prod, precio")
                ->fetchAll(PDO::FETCH_OBJ);
            foreach ($c->Detalle as $k => $d) {
                $c->Detalle[$k]->{'Producto'} = $this->db->query("SELECT pro_nom, pro_pre FROM v_productos WHERE id_pres = " . $d->id_prod)
                    ->fetch(PDO::FETCH_OBJ);
            }
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function impresion_reparto_pedido($id_venta)
    {
        try {
            $stm = $this->db->prepare("SELECT v.id_pedido, v.id_cliente,v.tipo_cliente , v.desc_tp, v.id_tpag, v.paga_con, v.comision_delivery, d.nro_pedido, d.hora_entrega, v.dni_cliente, v.ruc_cliente , v.nombre_cliente, v.direccion_cliente, v.referencia_cliente, v.telefono_cliente  FROM v_pedido_delivery AS v INNER JOIN tm_pedido_delivery AS d ON v.id_pedido = d.id_pedido WHERE v.id_pedido = ?");
            $stm->execute(array($id_venta));
            $c = $stm->fetch(PDO::FETCH_OBJ);
            $c->{'Cliente'} = $this->db->query("SELECT * FROM v_clientes WHERE id_cliente = " . $c->id_cliente)
                ->fetch(PDO::FETCH_OBJ);
            /* Traemos el detalle */
            $c->{'Detalle'} = $this->db->query("SELECT id_pres,SUM(cant) AS cantidad, precio FROM tm_detalle_pedido WHERE id_pedido = " . $c->id_pedido . " GROUP BY id_pres, precio")
                ->fetchAll(PDO::FETCH_OBJ);
            foreach ($c->Detalle as $k => $d) {
                $c->Detalle[$k]->{'Producto'} = $this->db->query("SELECT pro_nom, pro_pre FROM v_productos WHERE id_pres = " . $d->id_pres)
                    ->fetch(PDO::FETCH_OBJ);
            }

            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function contador_comanda()
    {
        try {
            $stm = $this->db->prepare("SELECT COUNT(*) AS correlativo FROM tm_detalle_pedido GROUP BY id_pedido,fecha_pedido");
            $stm->execute();
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    public function alert_pedidos_programados()
    {
        try {
            $stm = $this->db->prepare("SELECT MIN(pd.hora_entrega) AS hora_entrega, pd.id_pedido, pd.nombre_cliente, pd.nro_pedido FROM tm_pedido_delivery AS pd INNER JOIN tm_pedido AS p ON pd.id_pedido = p.id_pedido WHERE pd.pedido_programado = 1 AND p.estado = 'a'");
            $stm->execute();
            $c = $stm->fetch(PDO::FETCH_OBJ);
            return $c;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }
    /* FIN IMPRESION */
    public function control_stock_pedido($data)
    {
        try {
            $data['id_pres'];
            $consulta = "SELECT * FROM `v_stock_pedido` WHERE `id_ins` = :id_pedido";
            $result = $this->db->prepare($consulta);
            $result->bindParam(':id_pedido', $data['id_pres'], PDO::PARAM_INT);
            $result->execute();
            $row = $result->fetch(PDO::FETCH_OBJ);
            if ($row) {
                return $row;
            } else {
                return 0;
            }
            // return $row;
        } catch (Exception $e) {
            return false;
        }
    }
    public function stock_list($data)
    {
        try {
            $stm = $this->db->prepare("SELECT * FROM v_stock WHERE id_tipo_ins LIKE ? AND debajo_stock LIKE ?");
            $stm->execute(array($data['tipo_ins'], $data['stock_min']));
            $c = $stm->fetchAll(PDO::FETCH_OBJ);
            foreach ($c as $k => $d) {
                $c[$k]->{'Producto'} = $this->db->query("SELECT * FROM v_insprod WHERE id_tipo_ins = " . $d->id_tipo_ins . " AND id_ins = " . $d->id_ins)
                    ->fetch(PDO::FETCH_OBJ);
            }
            $data = array("data" => $c);
            $json = json_encode($data);
            echo $json;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }


}

