<?php
/**
 * CuentasPorCobrar.php
 * Módulo de Cuentas por Cobrar (CXC)
 * Maneja ventas a crédito y pagos parciales
 */

// Prevenir acceso directo
if (!defined('BASEPATH')) exit('No direct script access allowed');

switch ($tipo) {
    // ============================================================
    // OBTENER CUENTAS POR COBRAR
    // ============================================================
    case 'getCuentasPorCobrar':
        try {
            $fecha_inicio = isset($datapost['fecha_inicio']) ? $datapost['fecha_inicio'] : date('Y-m-01');
            $fecha_fin = isset($datapost['fecha_fin']) ? $datapost['fecha_fin'] : date('Y-m-t');
            $cliente_id = isset($datapost['cliente_id']) ? intval($datapost['cliente_id']) : null;
            $urgencia = isset($datapost['urgencia']) ? $datapost['urgencia'] : null;

            $sql = "SELECT
                        v.id,
                        v.folio,
                        v.cliente_id,
                        c.nombre AS cliente_nombre,
                        c.nombre_comercial AS cliente_nombre_comercial,
                        c.dias_credito,
                        c.monto_credito_maximo,
                        c.saldo_credito_usado,
                        v.total,
                        v.saldo_pendiente,
                        v.metodo_pago,
                        v.estatus_pago,
                        v.fecha_creacion AS fecha_venta,
                        DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY) AS fecha_vencimiento,
                        DATEDIFF(CURDATE(), v.fecha_creacion) AS dias_transcurridos,
                        DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY), CURDATE()) AS dias_para_vencer,
                        CASE
                            WHEN DATEDIFF(CURDATE(), DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY)) > 0 THEN 'vencida'
                            WHEN DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY), CURDATE()) <= 7 THEN 'proxima'
                            ELSE 'normal'
                        END AS urgencia,
                        (SELECT COUNT(*) FROM venta_pagos WHERE venta_id = v.id) AS num_abonos,
                        COALESCE((SELECT SUM(monto) FROM venta_pagos WHERE venta_id = v.id), 0) AS total_abonado
                    FROM ventas v
                    INNER JOIN clientes c ON v.cliente_id = c.id
                    WHERE v.metodo_pago IN ('credito', 'mixto')
                    AND v.estatus_pago = 'pendiente'
                    AND v.saldo_pendiente > 0
                    AND DATE(v.fecha_creacion) BETWEEN ? AND ?";

            $params = [$fecha_inicio, $fecha_fin];
            $types = "ss";

            if ($cliente_id) {
                $sql .= " AND v.cliente_id = ?";
                $params[] = $cliente_id;
                $types .= "i";
            }

            if ($urgencia && $urgencia !== 'todos') {
                switch ($urgencia) {
                    case 'vencida':
                        $sql .= " AND DATEDIFF(CURDATE(), DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY)) > 0";
                        break;
                    case 'proxima':
                        $sql .= " AND DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY), CURDATE()) BETWEEN 0 AND 7";
                        break;
                    case 'normal':
                        $sql .= " AND DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY), CURDATE()) > 7";
                        break;
                }
            }

            $sql .= " ORDER BY fecha_vencimiento ASC, v.total DESC";

            $stmt = $conn->prepare($sql);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();

            $cuentas = [];
            $total_pendiente = 0;
            $total_vencido = 0;
            $cuentas_vencidas = 0;
            $cuentas_proximas = 0;

            while ($row = $result->fetch_assoc()) {
                $cuenta = [
                    'id' => intval($row['id']),
                    'folio' => $row['folio'],
                    'cliente_id' => intval($row['cliente_id']),
                    'cliente_nombre' => $row['cliente_nombre'],
                    'cliente_nombre_comercial' => $row['cliente_nombre_comercial'],
                    'dias_credito' => intval($row['dias_credito']),
                    'total' => floatval($row['total']),
                    'saldo_pendiente' => floatval($row['saldo_pendiente']),
                    'total_abonado' => floatval($row['total_abonado']),
                    'num_abonos' => intval($row['num_abonos']),
                    'fecha_venta' => $row['fecha_venta'],
                    'fecha_vencimiento' => $row['fecha_vencimiento'],
                    'dias_transcurridos' => intval($row['dias_transcurridos']),
                    'dias_para_vencer' => intval($row['dias_para_vencer']),
                    'urgencia' => $row['urgencia']
                ];

                $cuentas[] = $cuenta;
                $total_pendiente += $cuenta['saldo_pendiente'];

                if ($cuenta['urgencia'] === 'vencida') {
                    $total_vencido += $cuenta['saldo_pendiente'];
                    $cuentas_vencidas++;
                } elseif ($cuenta['urgencia'] === 'proxima') {
                    $cuentas_proximas++;
                }
            }

            sendResponse(true, "Cuentas por cobrar obtenidas", [
                'cuentas' => $cuentas,
                'resumen' => [
                    'total_cuentas' => count($cuentas),
                    'total_pendiente' => $total_pendiente,
                    'total_vencido' => $total_vencido,
                    'cuentas_vencidas' => $cuentas_vencidas,
                    'cuentas_proximas' => $cuentas_proximas
                ]
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener cuentas por cobrar: " . $e->getMessage());
        }
        break;

    // ============================================================
    // REGISTRAR PAGO/ABONO
    // ============================================================
    case 'registrarPagoCXC':
        $venta_id = isset($datapost['venta_id']) ? intval($datapost['venta_id']) : 0;
        $monto = isset($datapost['monto']) ? floatval($datapost['monto']) : 0;
        $metodo_pago = isset($datapost['metodo_pago']) ? trim($datapost['metodo_pago']) : 'efectivo';
        $referencia = isset($datapost['referencia']) ? trim($datapost['referencia']) : null;
        $notas = isset($datapost['notas']) ? trim($datapost['notas']) : null;
        $registrado_por = isset($datapost['usuario_id']) ? intval($datapost['usuario_id']) : 0;

        // Validaciones básicas
        if ($venta_id <= 0) {
            sendResponse(false, "ID de venta requerido");
        }
        if ($monto <= 0) {
            sendResponse(false, "El monto debe ser mayor a cero");
        }
        if ($registrado_por <= 0) {
            sendResponse(false, "Usuario requerido para registrar el pago");
        }
        if (!in_array($metodo_pago, ['efectivo', 'tarjeta', 'transferencia'])) {
            sendResponse(false, "Método de pago no válido");
        }

        try {
            // Iniciar transacción
            $conn->begin_transaction();

            // Obtener venta actual con bloqueo
            $stmt = $conn->prepare("
                SELECT v.id, v.cliente_id, v.total, v.saldo_pendiente, v.estatus_pago,
                       c.saldo_credito_usado
                FROM ventas v
                INNER JOIN clientes c ON v.cliente_id = c.id
                WHERE v.id = ?
                FOR UPDATE
            ");
            $stmt->bind_param("i", $venta_id);
            $stmt->execute();
            $result = $stmt->get_result();
            $venta = $result->fetch_assoc();

            if (!$venta) {
                $conn->rollback();
                sendResponse(false, "Venta no encontrada");
            }

            if ($venta['estatus_pago'] === 'pagado') {
                $conn->rollback();
                sendResponse(false, "Esta cuenta ya está completamente pagada");
            }

            $saldo_actual = floatval($venta['saldo_pendiente']);

            if ($saldo_actual <= 0) {
                $conn->rollback();
                sendResponse(false, "Esta cuenta no tiene saldo pendiente");
            }

            if ($monto > $saldo_actual) {
                $conn->rollback();
                sendResponse(false, "El monto ($" . number_format($monto, 2) . ") excede el saldo pendiente ($" . number_format($saldo_actual, 2) . ")");
            }

            // Insertar registro de pago
            $stmt = $conn->prepare("
                INSERT INTO venta_pagos (venta_id, monto, metodo_pago, referencia, notas, registrado_por, fecha_pago)
                VALUES (?, ?, ?, ?, ?, ?, NOW())
            ");
            $stmt->bind_param("idsssi", $venta_id, $monto, $metodo_pago, $referencia, $notas, $registrado_por);

            if (!$stmt->execute()) {
                $conn->rollback();
                sendResponse(false, "Error al registrar el pago");
            }

            $pago_id = $conn->insert_id;

            // Calcular nuevo saldo
            $nuevo_saldo = $saldo_actual - $monto;
            $nuevo_estatus = $nuevo_saldo <= 0.01 ? 'pagado' : 'pendiente'; // Tolerancia de centavos

            // Actualizar saldo_pendiente y estatus de la venta
            $stmt = $conn->prepare("
                UPDATE ventas
                SET saldo_pendiente = ?, estatus_pago = ?
                WHERE id = ?
            ");
            $nuevo_saldo_final = max(0, $nuevo_saldo);
            $stmt->bind_param("dsi", $nuevo_saldo_final, $nuevo_estatus, $venta_id);

            if (!$stmt->execute()) {
                $conn->rollback();
                sendResponse(false, "Error al actualizar el saldo de la venta");
            }

            // Actualizar saldo_credito_usado del cliente (reducir)
            $stmt = $conn->prepare("
                UPDATE clientes
                SET saldo_credito_usado = GREATEST(0, saldo_credito_usado - ?)
                WHERE id = ?
            ");
            $stmt->bind_param("di", $monto, $venta['cliente_id']);

            if (!$stmt->execute()) {
                $conn->rollback();
                sendResponse(false, "Error al actualizar el crédito del cliente");
            }

            // Confirmar transacción
            $conn->commit();

            $mensaje = $nuevo_estatus === 'pagado'
                ? "Pago registrado. Cuenta liquidada completamente."
                : "Abono registrado exitosamente. Nuevo saldo: $" . number_format($nuevo_saldo_final, 2);

            sendResponse(true, $mensaje, [
                'pago_id' => $pago_id,
                'saldo_anterior' => $saldo_actual,
                'monto_pagado' => $monto,
                'nuevo_saldo' => $nuevo_saldo_final,
                'cuenta_liquidada' => $nuevo_estatus === 'pagado'
            ]);

        } catch (Exception $e) {
            $conn->rollback();
            sendResponse(false, "Error al registrar pago: " . $e->getMessage());
        }
        break;

    // ============================================================
    // OBTENER HISTORIAL DE PAGOS DE UNA VENTA
    // ============================================================
    case 'getHistorialPagosVenta':
        $venta_id = isset($datapost['venta_id']) ? intval($datapost['venta_id']) : 0;

        if ($venta_id <= 0) {
            sendResponse(false, "ID de venta requerido");
        }

        try {
            // Obtener info de la venta
            $stmt = $conn->prepare("
                SELECT v.id, v.folio, v.total, v.saldo_pendiente, v.fecha_creacion,
                       c.nombre AS cliente_nombre
                FROM ventas v
                INNER JOIN clientes c ON v.cliente_id = c.id
                WHERE v.id = ?
            ");
            $stmt->bind_param("i", $venta_id);
            $stmt->execute();
            $result = $stmt->get_result();
            $venta = $result->fetch_assoc();

            if (!$venta) {
                sendResponse(false, "Venta no encontrada");
            }

            // Obtener historial de pagos
            $stmt = $conn->prepare("
                SELECT vp.id, vp.monto, vp.metodo_pago, vp.referencia, vp.notas,
                       vp.fecha_pago, u.nombre AS registrado_por_nombre
                FROM venta_pagos vp
                LEFT JOIN usuarios u ON vp.registrado_por = u.id
                WHERE vp.venta_id = ?
                ORDER BY vp.fecha_pago DESC
            ");
            $stmt->bind_param("i", $venta_id);
            $stmt->execute();
            $result = $stmt->get_result();

            $pagos = [];
            $total_abonado = 0;

            while ($row = $result->fetch_assoc()) {
                $pagos[] = [
                    'id' => intval($row['id']),
                    'monto' => floatval($row['monto']),
                    'metodo_pago' => $row['metodo_pago'],
                    'referencia' => $row['referencia'],
                    'notas' => $row['notas'],
                    'fecha_pago' => $row['fecha_pago'],
                    'registrado_por' => $row['registrado_por_nombre']
                ];
                $total_abonado += floatval($row['monto']);
            }

            sendResponse(true, "Historial de pagos obtenido", [
                'venta' => [
                    'id' => intval($venta['id']),
                    'folio' => $venta['folio'],
                    'total' => floatval($venta['total']),
                    'saldo_pendiente' => floatval($venta['saldo_pendiente']),
                    'fecha_creacion' => $venta['fecha_creacion'],
                    'cliente_nombre' => $venta['cliente_nombre']
                ],
                'pagos' => $pagos,
                'total_abonado' => $total_abonado,
                'num_pagos' => count($pagos)
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener historial: " . $e->getMessage());
        }
        break;

    // ============================================================
    // RESUMEN CXC POR CLIENTE
    // ============================================================
    case 'getResumenCXCPorCliente':
        try {
            $sql = "SELECT
                        c.id AS cliente_id,
                        c.nombre AS cliente_nombre,
                        c.nombre_comercial,
                        c.dias_credito,
                        c.monto_credito_maximo,
                        c.saldo_credito_usado,
                        COUNT(v.id) AS num_cuentas,
                        SUM(v.saldo_pendiente) AS total_pendiente,
                        MIN(v.fecha_creacion) AS cuenta_mas_antigua,
                        MAX(
                            DATEDIFF(CURDATE(), DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY))
                        ) AS max_dias_vencido,
                        SUM(CASE
                            WHEN DATEDIFF(CURDATE(), DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY)) > 0
                            THEN v.saldo_pendiente ELSE 0
                        END) AS monto_vencido,
                        SUM(CASE
                            WHEN DATEDIFF(CURDATE(), DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY)) > 0
                            THEN 1 ELSE 0
                        END) AS cuentas_vencidas
                    FROM clientes c
                    INNER JOIN ventas v ON c.id = v.cliente_id
                    WHERE v.metodo_pago IN ('credito', 'mixto')
                    AND v.estatus_pago = 'pendiente'
                    AND v.saldo_pendiente > 0
                    GROUP BY c.id
                    ORDER BY total_pendiente DESC";

            $result = $conn->query($sql);

            if (!$result) {
                sendResponse(false, "Error en consulta: " . $conn->error);
            }

            $resumen = [];
            $total_general = 0;
            $total_vencido_general = 0;

            while ($row = $result->fetch_assoc()) {
                $cliente = [
                    'cliente_id' => intval($row['cliente_id']),
                    'cliente_nombre' => $row['cliente_nombre'],
                    'nombre_comercial' => $row['nombre_comercial'],
                    'dias_credito' => intval($row['dias_credito']),
                    'monto_credito_maximo' => floatval($row['monto_credito_maximo']),
                    'saldo_credito_usado' => floatval($row['saldo_credito_usado']),
                    'credito_disponible' => floatval($row['monto_credito_maximo']) - floatval($row['saldo_credito_usado']),
                    'num_cuentas' => intval($row['num_cuentas']),
                    'total_pendiente' => floatval($row['total_pendiente']),
                    'cuenta_mas_antigua' => $row['cuenta_mas_antigua'],
                    'max_dias_vencido' => intval($row['max_dias_vencido']),
                    'monto_vencido' => floatval($row['monto_vencido']),
                    'cuentas_vencidas' => intval($row['cuentas_vencidas']),
                    'tiene_vencidas' => intval($row['max_dias_vencido']) > 0
                ];

                $resumen[] = $cliente;
                $total_general += $cliente['total_pendiente'];
                $total_vencido_general += $cliente['monto_vencido'];
            }

            sendResponse(true, "Resumen por cliente obtenido", [
                'clientes' => $resumen,
                'totales' => [
                    'num_clientes' => count($resumen),
                    'total_general' => $total_general,
                    'total_vencido' => $total_vencido_general
                ]
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener resumen: " . $e->getMessage());
        }
        break;

    // ============================================================
    // DETALLE DE UNA CUENTA CXC
    // ============================================================
    case 'getDetalleCuentaCXC':
        $venta_id = isset($datapost['venta_id']) ? intval($datapost['venta_id']) : 0;

        if ($venta_id <= 0) {
            sendResponse(false, "ID de venta requerido");
        }

        try {
            // Obtener información completa de la venta
            $stmt = $conn->prepare("
                SELECT
                    v.id, v.folio, v.cliente_id, v.total, v.subtotal, v.descuento,
                    v.saldo_pendiente, v.metodo_pago, v.estatus_pago, v.observaciones,
                    v.fecha_creacion, v.tipo_entrega, v.direccion_entrega,
                    c.nombre AS cliente_nombre,
                    c.nombre_comercial AS cliente_nombre_comercial,
                    c.dias_credito,
                    c.monto_credito_maximo,
                    c.saldo_credito_usado,
                    DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY) AS fecha_vencimiento,
                    DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL c.dias_credito DAY), CURDATE()) AS dias_para_vencer,
                    u.nombre AS vendedor_nombre
                FROM ventas v
                INNER JOIN clientes c ON v.cliente_id = c.id
                LEFT JOIN usuarios u ON v.usuario_id = u.id
                WHERE v.id = ?
            ");
            $stmt->bind_param("i", $venta_id);
            $stmt->execute();
            $result = $stmt->get_result();
            $venta = $result->fetch_assoc();

            if (!$venta) {
                sendResponse(false, "Venta no encontrada");
            }

            // Obtener productos de la venta
            $stmt = $conn->prepare("
                SELECT vd.cantidad, vd.precio_unitario, vd.subtotal,
                       vd.producto_nombre, p.codigo_corto
                FROM venta_detalles vd
                LEFT JOIN productos p ON vd.producto_id = p.id
                WHERE vd.venta_id = ?
            ");
            $stmt->bind_param("i", $venta_id);
            $stmt->execute();
            $result = $stmt->get_result();

            $productos = [];
            while ($row = $result->fetch_assoc()) {
                $productos[] = [
                    'codigo' => $row['codigo_corto'] ?? '',
                    'nombre' => $row['producto_nombre'],
                    'cantidad' => floatval($row['cantidad']),
                    'precio_unitario' => floatval($row['precio_unitario']),
                    'subtotal' => floatval($row['subtotal'])
                ];
            }

            // Obtener pagos realizados
            $stmt = $conn->prepare("
                SELECT vp.monto, vp.metodo_pago, vp.referencia, vp.notas,
                       vp.fecha_pago, u.nombre AS registrado_por
                FROM venta_pagos vp
                LEFT JOIN usuarios u ON vp.registrado_por = u.id
                WHERE vp.venta_id = ?
                ORDER BY vp.fecha_pago DESC
            ");
            $stmt->bind_param("i", $venta_id);
            $stmt->execute();
            $result = $stmt->get_result();

            $pagos = [];
            $total_abonado = 0;
            while ($row = $result->fetch_assoc()) {
                $pagos[] = [
                    'monto' => floatval($row['monto']),
                    'metodo_pago' => $row['metodo_pago'],
                    'referencia' => $row['referencia'],
                    'notas' => $row['notas'],
                    'fecha_pago' => $row['fecha_pago'],
                    'registrado_por' => $row['registrado_por']
                ];
                $total_abonado += floatval($row['monto']);
            }

            // Determinar urgencia
            $dias_para_vencer = intval($venta['dias_para_vencer']);
            $urgencia = 'normal';
            if ($dias_para_vencer < 0) {
                $urgencia = 'vencida';
            } elseif ($dias_para_vencer <= 7) {
                $urgencia = 'proxima';
            }

            sendResponse(true, "Detalle de cuenta obtenido", [
                'venta' => [
                    'id' => intval($venta['id']),
                    'folio' => $venta['folio'],
                    'total' => floatval($venta['total']),
                    'subtotal' => floatval($venta['subtotal']),
                    'descuento' => floatval($venta['descuento']),
                    'saldo_pendiente' => floatval($venta['saldo_pendiente']),
                    'total_abonado' => $total_abonado,
                    'fecha_creacion' => $venta['fecha_creacion'],
                    'fecha_vencimiento' => $venta['fecha_vencimiento'],
                    'dias_para_vencer' => $dias_para_vencer,
                    'urgencia' => $urgencia,
                    'observaciones' => $venta['observaciones'],
                    'vendedor' => $venta['vendedor_nombre']
                ],
                'cliente' => [
                    'id' => intval($venta['cliente_id']),
                    'nombre' => $venta['cliente_nombre'],
                    'nombre_comercial' => $venta['cliente_nombre_comercial'],
                    'dias_credito' => intval($venta['dias_credito']),
                    'monto_credito_maximo' => floatval($venta['monto_credito_maximo']),
                    'saldo_credito_usado' => floatval($venta['saldo_credito_usado'])
                ],
                'productos' => $productos,
                'pagos' => $pagos
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener detalle: " . $e->getMessage());
        }
        break;

    // ============================================================
    // REGISTRAR ABONO GLOBAL DISTRIBUIDO
    // Distribuye un pago desde la cuenta más antigua hasta la más reciente
    // Guarda el monto total recibido para posterior facturación
    // ============================================================
    case 'registrarAbonoGlobalCXC':
        try {
            $cliente_id = isset($datapost['cliente_id']) ? intval($datapost['cliente_id']) : 0;
            $monto_total = isset($datapost['monto']) ? floatval($datapost['monto']) : 0;
            $metodo_pago = isset($datapost['metodo_pago']) ? trim($datapost['metodo_pago']) : 'efectivo';
            $referencia = isset($datapost['referencia']) ? trim($datapost['referencia']) : '';
            $notas = isset($datapost['notas']) ? trim($datapost['notas']) : '';
            $registrado_por = isset($datapost['registrado_por']) ? intval($datapost['registrado_por']) : 0;

            // Validaciones
            if ($cliente_id <= 0) {
                sendResponse(false, "Debe seleccionar un cliente");
            }
            if ($monto_total <= 0) {
                sendResponse(false, "El monto debe ser mayor a cero");
            }
            if ($registrado_por <= 0) {
                sendResponse(false, "Usuario no válido");
            }

            // Obtener cuentas pendientes del cliente ordenadas por fecha (más antigua primero)
            $stmt = $conn->prepare("
                SELECT v.id, v.folio, v.total, v.saldo_pendiente, v.fecha_creacion
                FROM ventas v
                WHERE v.cliente_id = ?
                AND v.metodo_pago IN ('credito', 'mixto')
                AND v.estatus_pago = 'pendiente'
                AND v.saldo_pendiente > 0
                ORDER BY v.fecha_creacion ASC, v.id ASC
            ");
            $stmt->bind_param("i", $cliente_id);
            $stmt->execute();
            $result = $stmt->get_result();

            $cuentas_pendientes = [];
            $total_deuda = 0;
            while ($row = $result->fetch_assoc()) {
                $cuentas_pendientes[] = $row;
                $total_deuda += floatval($row['saldo_pendiente']);
            }

            if (count($cuentas_pendientes) === 0) {
                sendResponse(false, "El cliente no tiene cuentas pendientes");
            }

            // Iniciar transacción
            $conn->begin_transaction();

            // Generar folio para el pago del cliente
            $fecha_folio = date('Ymd');
            $stmt_folio = $conn->prepare("SELECT COUNT(*) + 1 as num FROM pagos_clientes WHERE DATE(fecha_pago) = CURDATE()");
            $stmt_folio->execute();
            $num_folio = $stmt_folio->get_result()->fetch_assoc()['num'];
            $folio_pago = "PAG-{$fecha_folio}-" . str_pad($num_folio, 4, '0', STR_PAD_LEFT);

            // Calcular montos
            $monto_aplicado = min($monto_total, $total_deuda);
            $monto_sobrante = max(0, $monto_total - $total_deuda);

            // Insertar registro principal del pago del cliente
            $stmt_pago_cliente = $conn->prepare("
                INSERT INTO pagos_clientes (
                    folio, cliente_id, monto_recibido, monto_aplicado, monto_sobrante,
                    metodo_pago, referencia, notas, cuentas_afectadas, cuentas_liquidadas,
                    registrado_por, fecha_pago
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, 0, ?, NOW())
            ");
            $stmt_pago_cliente->bind_param("sidddssis",
                $folio_pago,
                $cliente_id,
                $monto_total,
                $monto_aplicado,
                $monto_sobrante,
                $metodo_pago,
                $referencia,
                $notas,
                $registrado_por
            );
            $stmt_pago_cliente->execute();
            $pago_cliente_id = $conn->insert_id;

            // Distribuir el pago en las cuentas
            $monto_restante = $monto_total;
            $pagos_aplicados = [];
            $cuentas_liquidadas = 0;
            $total_credito_liberado = 0;

            foreach ($cuentas_pendientes as $cuenta) {
                if ($monto_restante <= 0) break;

                $saldo_cuenta = floatval($cuenta['saldo_pendiente']);
                $monto_aplicar = min($monto_restante, $saldo_cuenta);
                $nuevo_saldo = $saldo_cuenta - $monto_aplicar;

                // Registrar el pago para esta cuenta (vinculado al pago_cliente)
                $nota_pago = $notas ? $notas . " (Pago global {$folio_pago})" : "Pago global {$folio_pago}";
                $stmt_pago = $conn->prepare("
                    INSERT INTO venta_pagos (venta_id, monto, metodo_pago, referencia, notas, registrado_por, pago_cliente_id, fecha_pago)
                    VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
                ");
                $stmt_pago->bind_param("idsssii",
                    $cuenta['id'],
                    $monto_aplicar,
                    $metodo_pago,
                    $referencia,
                    $nota_pago,
                    $registrado_por,
                    $pago_cliente_id
                );
                $stmt_pago->execute();

                // Actualizar saldo de la venta
                if ($nuevo_saldo <= 0) {
                    // Cuenta liquidada
                    $stmt_update = $conn->prepare("
                        UPDATE ventas SET saldo_pendiente = 0, estatus_pago = 'pagado' WHERE id = ?
                    ");
                    $stmt_update->bind_param("i", $cuenta['id']);
                    $cuentas_liquidadas++;
                } else {
                    // Aún queda saldo
                    $stmt_update = $conn->prepare("
                        UPDATE ventas SET saldo_pendiente = ? WHERE id = ?
                    ");
                    $stmt_update->bind_param("di", $nuevo_saldo, $cuenta['id']);
                }
                $stmt_update->execute();

                // Acumular crédito liberado
                $total_credito_liberado += $monto_aplicar;

                $pagos_aplicados[] = [
                    'venta_id' => intval($cuenta['id']),
                    'folio' => $cuenta['folio'],
                    'saldo_anterior' => $saldo_cuenta,
                    'monto_aplicado' => $monto_aplicar,
                    'saldo_nuevo' => $nuevo_saldo,
                    'liquidada' => $nuevo_saldo <= 0
                ];

                $monto_restante -= $monto_aplicar;
            }

            // Actualizar contadores en pagos_clientes
            $stmt_update_pago = $conn->prepare("
                UPDATE pagos_clientes
                SET cuentas_afectadas = ?, cuentas_liquidadas = ?
                WHERE id = ?
            ");
            $num_afectadas = count($pagos_aplicados);
            $stmt_update_pago->bind_param("iii", $num_afectadas, $cuentas_liquidadas, $pago_cliente_id);
            $stmt_update_pago->execute();

            // Actualizar saldo de crédito usado del cliente
            $stmt_cliente = $conn->prepare("
                UPDATE clientes SET saldo_credito_usado = GREATEST(0, saldo_credito_usado - ?) WHERE id = ?
            ");
            $stmt_cliente->bind_param("di", $total_credito_liberado, $cliente_id);
            $stmt_cliente->execute();

            // Confirmar transacción
            $conn->commit();

            $sobrante = $monto_restante > 0 ? $monto_restante : 0;
            $mensaje = "Pago {$folio_pago} de $" . number_format($monto_total, 2) . " registrado correctamente";
            if ($cuentas_liquidadas > 0) {
                $mensaje .= ". Se liquidaron $cuentas_liquidadas cuenta(s)";
            }
            if ($sobrante > 0) {
                $mensaje .= ". Sobrante: $" . number_format($sobrante, 2);
            }

            sendResponse(true, $mensaje, [
                'pago_cliente_id' => $pago_cliente_id,
                'folio' => $folio_pago,
                'monto_recibido' => $monto_total,
                'monto_aplicado' => $monto_total - $sobrante,
                'sobrante' => $sobrante,
                'cuentas_afectadas' => count($pagos_aplicados),
                'cuentas_liquidadas' => $cuentas_liquidadas,
                'detalle_pagos' => $pagos_aplicados
            ]);

        } catch (Exception $e) {
            $conn->rollback();
            sendResponse(false, "Error al registrar abono global: " . $e->getMessage());
        }
        break;

    // ============================================================
    // OBTENER CUENTAS PENDIENTES DE UN CLIENTE (para abono global)
    // ============================================================
    case 'getCuentasPendientesCliente':
        try {
            $cliente_id = isset($datapost['cliente_id']) ? intval($datapost['cliente_id']) : 0;

            if ($cliente_id <= 0) {
                sendResponse(false, "Cliente no válido");
            }

            // Obtener información del cliente
            $stmt = $conn->prepare("
                SELECT id, nombre, nombre_comercial, dias_credito, monto_credito_maximo, saldo_credito_usado
                FROM clientes WHERE id = ?
            ");
            $stmt->bind_param("i", $cliente_id);
            $stmt->execute();
            $cliente = $stmt->get_result()->fetch_assoc();

            if (!$cliente) {
                sendResponse(false, "Cliente no encontrado");
            }

            // Obtener cuentas pendientes
            $stmt = $conn->prepare("
                SELECT
                    v.id,
                    v.folio,
                    v.total,
                    v.saldo_pendiente,
                    v.fecha_creacion AS fecha_venta,
                    DATE_ADD(v.fecha_creacion, INTERVAL ? DAY) AS fecha_vencimiento,
                    DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL ? DAY), CURDATE()) AS dias_para_vencer,
                    CASE
                        WHEN DATEDIFF(CURDATE(), DATE_ADD(v.fecha_creacion, INTERVAL ? DAY)) > 0 THEN 'vencida'
                        WHEN DATEDIFF(DATE_ADD(v.fecha_creacion, INTERVAL ? DAY), CURDATE()) <= 7 THEN 'proxima'
                        ELSE 'normal'
                    END AS urgencia
                FROM ventas v
                WHERE v.cliente_id = ?
                AND v.metodo_pago IN ('credito', 'mixto')
                AND v.estatus_pago = 'pendiente'
                AND v.saldo_pendiente > 0
                ORDER BY v.fecha_creacion ASC, v.id ASC
            ");
            $dias = intval($cliente['dias_credito']);
            $stmt->bind_param("iiiii", $dias, $dias, $dias, $dias, $cliente_id);
            $stmt->execute();
            $result = $stmt->get_result();

            $cuentas = [];
            $total_pendiente = 0;
            while ($row = $result->fetch_assoc()) {
                $cuentas[] = [
                    'id' => intval($row['id']),
                    'folio' => $row['folio'],
                    'total' => floatval($row['total']),
                    'saldo_pendiente' => floatval($row['saldo_pendiente']),
                    'fecha_venta' => $row['fecha_venta'],
                    'fecha_vencimiento' => $row['fecha_vencimiento'],
                    'dias_para_vencer' => intval($row['dias_para_vencer']),
                    'urgencia' => $row['urgencia']
                ];
                $total_pendiente += floatval($row['saldo_pendiente']);
            }

            sendResponse(true, "Cuentas pendientes obtenidas", [
                'cliente' => [
                    'id' => intval($cliente['id']),
                    'nombre' => $cliente['nombre'],
                    'nombre_comercial' => $cliente['nombre_comercial'],
                    'dias_credito' => intval($cliente['dias_credito']),
                    'monto_credito_maximo' => floatval($cliente['monto_credito_maximo']),
                    'saldo_credito_usado' => floatval($cliente['saldo_credito_usado'])
                ],
                'cuentas' => $cuentas,
                'total_pendiente' => $total_pendiente,
                'num_cuentas' => count($cuentas)
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener cuentas: " . $e->getMessage());
        }
        break;

    // ============================================================
    // OBTENER PAGOS DE CLIENTES (para facturación)
    // ============================================================
    case 'getPagosClientes':
        try {
            $cliente_id = isset($datapost['cliente_id']) && $datapost['cliente_id'] !== '' ? intval($datapost['cliente_id']) : null;
            $fecha_inicio = !empty($datapost['fecha_inicio']) ? $datapost['fecha_inicio'] : date('Y-01-01');
            $fecha_fin = !empty($datapost['fecha_fin']) ? $datapost['fecha_fin'] : date('Y-12-31');
            $solo_sin_facturar = isset($datapost['solo_sin_facturar']) ? (bool)$datapost['solo_sin_facturar'] : false;
            // Tambien aceptar el parametro 'facturado' con valor 0 para filtrar solo sin facturar
            $facturado_param = isset($datapost['facturado']) ? $datapost['facturado'] : null;
            $folio = isset($datapost['folio']) && $datapost['folio'] !== '' ? trim($datapost['folio']) : null;

            $sql = "SELECT
                        pc.id,
                        pc.folio,
                        pc.cliente_id,
                        c.nombre AS cliente_nombre,
                        c.nombre_comercial AS cliente_nombre_comercial,
                        pc.monto_recibido,
                        pc.monto_aplicado,
                        pc.monto_sobrante,
                        pc.metodo_pago,
                        pc.referencia,
                        pc.notas,
                        pc.cuentas_afectadas,
                        pc.cuentas_liquidadas,
                        pc.fecha_pago,
                        pc.facturado,
                        pc.factura_id,
                        pc.fecha_facturacion,
                        u.nombre AS registrado_por_nombre
                    FROM pagos_clientes pc
                    INNER JOIN clientes c ON pc.cliente_id = c.id
                    LEFT JOIN usuarios u ON pc.registrado_por = u.id
                    WHERE DATE(pc.fecha_pago) BETWEEN ? AND ?";

            $params = [$fecha_inicio, $fecha_fin];
            $types = "ss";

            if ($cliente_id) {
                $sql .= " AND pc.cliente_id = ?";
                $params[] = $cliente_id;
                $types .= "i";
            }

            if ($folio) {
                $sql .= " AND pc.folio LIKE ?";
                $params[] = "%$folio%";
                $types .= "s";
            }

            // Filtrar por facturado (0 = sin facturar, 1 = facturado)
            if ($solo_sin_facturar || $facturado_param === 0 || $facturado_param === '0') {
                $sql .= " AND pc.facturado = 0";
            } elseif ($facturado_param === 1 || $facturado_param === '1') {
                $sql .= " AND pc.facturado = 1";
            }

            $sql .= " ORDER BY pc.fecha_pago DESC";

            $stmt = $conn->prepare($sql);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();

            $pagos = [];
            $total_recibido = 0;
            $total_sin_facturar = 0;

            while ($row = $result->fetch_assoc()) {
                $pagos[] = [
                    'id' => intval($row['id']),
                    'folio' => $row['folio'],
                    'cliente_id' => intval($row['cliente_id']),
                    'cliente_nombre' => $row['cliente_nombre'],
                    'cliente_nombre_comercial' => $row['cliente_nombre_comercial'],
                    'monto_recibido' => floatval($row['monto_recibido']),
                    'monto_aplicado' => floatval($row['monto_aplicado']),
                    'monto_sobrante' => floatval($row['monto_sobrante']),
                    'metodo_pago' => $row['metodo_pago'],
                    'referencia' => $row['referencia'],
                    'notas' => $row['notas'],
                    'cuentas_afectadas' => intval($row['cuentas_afectadas']),
                    'cuentas_liquidadas' => intval($row['cuentas_liquidadas']),
                    'fecha_pago' => $row['fecha_pago'],
                    'facturado' => (bool)$row['facturado'],
                    'factura_id' => $row['factura_id'] ? intval($row['factura_id']) : null,
                    'fecha_facturacion' => $row['fecha_facturacion'],
                    'registrado_por' => $row['registrado_por_nombre']
                ];

                $total_recibido += floatval($row['monto_recibido']);
                if (!$row['facturado']) {
                    $total_sin_facturar += floatval($row['monto_recibido']);
                }
            }

            sendResponse(true, "Pagos obtenidos", [
                'pagos' => $pagos,
                'resumen' => [
                    'total_pagos' => count($pagos),
                    'total_recibido' => $total_recibido,
                    'total_sin_facturar' => $total_sin_facturar
                ]
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener pagos: " . $e->getMessage());
        }
        break;

    // ============================================================
    // OBTENER DETALLE DE UN PAGO DE CLIENTE
    // ============================================================
    case 'getDetallePagoCliente':
        try {
            $pago_id = isset($datapost['pago_id']) ? intval($datapost['pago_id']) : 0;

            if ($pago_id <= 0) {
                sendResponse(false, "ID de pago no válido");
            }

            // Obtener datos del pago
            $stmt = $conn->prepare("
                SELECT pc.*, c.nombre AS cliente_nombre, c.nombre_comercial,
                       c.rfc, c.email, u.nombre AS registrado_por_nombre
                FROM pagos_clientes pc
                INNER JOIN clientes c ON pc.cliente_id = c.id
                LEFT JOIN usuarios u ON pc.registrado_por = u.id
                WHERE pc.id = ?
            ");
            $stmt->bind_param("i", $pago_id);
            $stmt->execute();
            $pago = $stmt->get_result()->fetch_assoc();

            if (!$pago) {
                sendResponse(false, "Pago no encontrado");
            }

            // Obtener los pagos individuales (distribución)
            $stmt = $conn->prepare("
                SELECT vp.*, v.folio AS venta_folio
                FROM venta_pagos vp
                INNER JOIN ventas v ON vp.venta_id = v.id
                WHERE vp.pago_cliente_id = ?
                ORDER BY vp.fecha_pago ASC
            ");
            $stmt->bind_param("i", $pago_id);
            $stmt->execute();
            $result = $stmt->get_result();

            $distribucion = [];
            while ($row = $result->fetch_assoc()) {
                $distribucion[] = [
                    'venta_id' => intval($row['venta_id']),
                    'venta_folio' => $row['venta_folio'],
                    'monto' => floatval($row['monto']),
                    'fecha_pago' => $row['fecha_pago']
                ];
            }

            sendResponse(true, "Detalle de pago obtenido", [
                'pago' => [
                    'id' => intval($pago['id']),
                    'folio' => $pago['folio'],
                    'monto_recibido' => floatval($pago['monto_recibido']),
                    'monto_aplicado' => floatval($pago['monto_aplicado']),
                    'monto_sobrante' => floatval($pago['monto_sobrante']),
                    'metodo_pago' => $pago['metodo_pago'],
                    'referencia' => $pago['referencia'],
                    'notas' => $pago['notas'],
                    'cuentas_afectadas' => intval($pago['cuentas_afectadas']),
                    'cuentas_liquidadas' => intval($pago['cuentas_liquidadas']),
                    'fecha_pago' => $pago['fecha_pago'],
                    'facturado' => (bool)$pago['facturado'],
                    'factura_id' => $pago['factura_id'] ? intval($pago['factura_id']) : null,
                    'fecha_facturacion' => $pago['fecha_facturacion'],
                    'registrado_por' => $pago['registrado_por_nombre']
                ],
                'cliente' => [
                    'id' => intval($pago['cliente_id']),
                    'nombre' => $pago['cliente_nombre'],
                    'nombre_comercial' => $pago['nombre_comercial'],
                    'rfc' => $pago['rfc'],
                    'email' => $pago['email']
                ],
                'distribucion' => $distribucion
            ]);

        } catch (Exception $e) {
            sendResponse(false, "Error al obtener detalle: " . $e->getMessage());
        }
        break;

    // ============================================================
    // MARCAR PAGO COMO FACTURADO
    // ============================================================
    case 'marcarPagoFacturado':
        try {
            $pago_id = isset($datapost['pago_id']) ? intval($datapost['pago_id']) : 0;
            $factura_id = isset($datapost['factura_id']) ? intval($datapost['factura_id']) : null;

            if ($pago_id <= 0) {
                sendResponse(false, "ID de pago no válido");
            }

            $stmt = $conn->prepare("
                UPDATE pagos_clientes
                SET facturado = 1, factura_id = ?, fecha_facturacion = NOW()
                WHERE id = ?
            ");
            $stmt->bind_param("ii", $factura_id, $pago_id);
            $stmt->execute();

            if ($stmt->affected_rows > 0) {
                sendResponse(true, "Pago marcado como facturado");
            } else {
                sendResponse(false, "No se pudo actualizar el pago");
            }

        } catch (Exception $e) {
            sendResponse(false, "Error: " . $e->getMessage());
        }
        break;

    default:
        sendResponse(false, "Operación no válida para cuentas por cobrar");
        break;
}
