-- ============================================
-- MIGRACIÓN 009: Optimización de calulo_boleta
-- Fecha: 2026-01-23
-- 
-- OPTIMIZACIONES:
-- - Reducción de ~30 consultas a ~7 consultas
-- - 1 consulta a vista_ingreso_lecturas (antes ~15)
-- - 1 consulta a tipos_cargo (antes 11)
-- - Consultas combinadas para deudas y repactaciones
-- 
-- LÓGICA DE NEGOCIO: 100% INTACTA
-- ============================================

DROP PROCEDURE IF EXISTS calulo_boleta;

DELIMITER //

CREATE PROCEDURE `calulo_boleta`(IN p_socio INT, IN p_lant INT, IN p_lact INT)
BEGIN
    -- ============================================
    -- DECLARACIÓN DE VARIABLES
    -- ============================================
    
    -- Datos del cliente y tarifa (de vista_ingreso_lecturas)
    DECLARE v_precio_metro3 INT DEFAULT 0;
    DECLARE v_sobreconsumo1 INT DEFAULT 0;
    DECLARE v_inicio1 INT DEFAULT 0;
    DECLARE v_inicio2 INT DEFAULT 0;
    DECLARE v_inicio3 INT DEFAULT 0;
    DECLARE v_limite_subsidio INT DEFAULT 0;
    DECLARE v_porcentaje_subsidio INT DEFAULT 0;
    DECLARE v_cargo_fijo_caneria INT DEFAULT 0;
    DECLARE v_alcantarillado INT DEFAULT 0;
    DECLARE v_cuota_mortuoria_flag INT DEFAULT 0;
    DECLARE v_valor_cuota_mortuoria INT DEFAULT 0;
    DECLARE v_multa_atraso_tarifa INT DEFAULT 0;
    DECLARE v_corte_reposicion INT DEFAULT 0;
    DECLARE v_corte_matriz INT DEFAULT 0;
    
    -- Datos del cliente
    DECLARE v_id_ciudad INT;
    DECLARE v_id_tipo_documento INT DEFAULT 3;
    DECLARE v_numero_medidor VARCHAR(50) DEFAULT '';
    DECLARE v_estado_socio INT DEFAULT 0;
    
    -- Datos APR
    DECLARE v_fecha_facturacion VARCHAR(10);
    DECLARE v_porcentaje_multa INT DEFAULT 0;
    DECLARE v_tipo_multa INT DEFAULT 0;
    DECLARE v_impuesto INT DEFAULT 0;
    
    -- Multas del socio
    DECLARE v_multa_atraso_flag INT DEFAULT 0;
    DECLARE v_multa_corte_flag INT DEFAULT 0;
    DECLARE v_multa_matriz_flag INT DEFAULT 0;
    
    -- Cálculos de consumo
    DECLARE v_consumo_m3 INT;
    DECLARE v_metraje_base INT DEFAULT 0;
    DECLARE v_metraje_tramo1 INT DEFAULT 0;
    DECLARE v_metraje_tramo2 INT DEFAULT 0;
    DECLARE v_metraje_tramo3 INT DEFAULT 0;
    DECLARE v_consumo_total INT DEFAULT 0;
    
    -- Cálculos de cargos
    DECLARE v_cargo_fijo INT DEFAULT 0;
    DECLARE v_alcantarillado_valor INT DEFAULT 0;
    DECLARE v_cargo_mortuoria INT DEFAULT 0;
    DECLARE v_subsidio_consumo INT DEFAULT 0;
    DECLARE v_subsidio_cargo_fijo INT DEFAULT 0;
    DECLARE v_subsidio_total INT DEFAULT 0;
    
    -- Multas calculadas
    DECLARE v_multa_atraso_valor INT DEFAULT 0;
    DECLARE v_multa_corte_valor INT DEFAULT 0;
    DECLARE v_multa_matriz_valor INT DEFAULT 0;
    
    -- Totales
    DECLARE v_total_mes_actual INT DEFAULT 0;
    DECLARE v_saldo_anterior INT DEFAULT 0;
    DECLARE v_total_boleta INT DEFAULT 0;
    
    -- Repactación
    DECLARE v_tiene_repactacion INT DEFAULT 0;
    DECLARE v_valor_cuota INT DEFAULT 0;
    DECLARE v_no_cuotas INT DEFAULT 0;
    DECLARE v_ult_cuota_facturada INT DEFAULT 0;
    
    -- Lectura y boleta
    DECLARE v_fecha_lectura DATE;
    DECLARE v_fecha_vencimiento VARCHAR(20);
    DECLARE v_prox_id_boleta INT;
    
    -- IDs de tipos de cargo (para boletas_detalle)
    DECLARE v_tc_consumo_base INT;
    DECLARE v_tc_consumo_tramo1 INT;
    DECLARE v_tc_cargo_fijo INT;
    DECLARE v_tc_alcantarillado INT;
    DECLARE v_tc_mortuoria INT;
    DECLARE v_tc_multa_atraso INT;
    DECLARE v_tc_multa_corte INT;
    DECLARE v_tc_multa_matriz INT;
    DECLARE v_tc_subsidio INT;
    DECLARE v_tc_repactacion INT;
    DECLARE v_tc_saldo_anterior INT;
    
    -- Variables para snapshot (datos históricos del cliente y APR)
    DECLARE v_cliente_nombre VARCHAR(100) DEFAULT '';
    DECLARE v_cliente_rut VARCHAR(20) DEFAULT '';
    DECLARE v_cliente_direccion VARCHAR(100) DEFAULT '';
    DECLARE v_cliente_ciudad VARCHAR(50) DEFAULT 'Sin especificar';
    DECLARE v_cliente_sector VARCHAR(50) DEFAULT '';
    DECLARE v_apr_nombre VARCHAR(100) DEFAULT '';
    DECLARE v_apr_rut VARCHAR(20) DEFAULT '';
    DECLARE v_apr_direccion VARCHAR(100) DEFAULT '';
    DECLARE v_apr_comuna VARCHAR(50) DEFAULT '';
    DECLARE v_apr_telefono VARCHAR(25) DEFAULT '';
    DECLARE v_apr_representante VARCHAR(150) DEFAULT '';
    DECLARE v_apr_telefono_rep VARCHAR(25) DEFAULT '';

    -- ============================================
    -- CALCULAR CONSUMO
    -- ============================================
    SET v_consumo_m3 = p_lact - p_lant;

    -- ============================================
    -- CONSULTA 1: Obtener TODOS los datos de tarifa del cliente
    -- (Antes eran ~15 consultas separadas)
    -- ============================================
    SELECT 
        COALESCE(precio_metro_cubico, 600),
        COALESCE(sobreconsumo1, 750),
        COALESCE(inicio1, 21),
        COALESCE(inicio2, 0),
        COALESCE(inicio3, 0),
        COALESCE(limite_subisidio, 0),
        COALESCE(porcentaje_subsidio, 0),
        COALESCE(cargo_fijo_caneria, 0),
        COALESCE(alcantarillado, 0),
        COALESCE(cuota_mortuoria, 0),
        COALESCE(valor_cuota_mortuoria, 0),
        COALESCE(multa_atraso, 0),
        COALESCE(corte_reposicion, 0),
        COALESCE(corte_matriz, 0)
    INTO 
        v_precio_metro3,
        v_sobreconsumo1,
        v_inicio1,
        v_inicio2,
        v_inicio3,
        v_limite_subsidio,
        v_porcentaje_subsidio,
        v_cargo_fijo_caneria,
        v_alcantarillado,
        v_cuota_mortuoria_flag,
        v_valor_cuota_mortuoria,
        v_multa_atraso_tarifa,
        v_corte_reposicion,
        v_corte_matriz
    FROM vista_ingreso_lecturas 
    WHERE Id_cliente = p_socio
    LIMIT 1;

    -- ============================================
    -- CONSULTA 2: Datos del cliente (incluyendo ciudad y sector para snapshot)
    -- ============================================
    SELECT 
        COALESCE(c.id_ciudad, 0),
        COALESCE(c.id_tipo_documento, 3),
        COALESCE(c.numero_medidor, ''),
        COALESCE(c.estado_socio, 0),
        COALESCE(c.nombre_cliente, ''),
        COALESCE(c.rut_cliente, ''),
        COALESCE(c.direccion, ''),
        COALESCE(ci.nombre_ciudad, 'Sin especificar'),
        COALESCE(s.nombre_sector, '')
    INTO 
        v_id_ciudad,
        v_id_tipo_documento,
        v_numero_medidor,
        v_estado_socio,
        v_cliente_nombre,
        v_cliente_rut,
        v_cliente_direccion,
        v_cliente_ciudad,
        v_cliente_sector
    FROM clientes c
    LEFT JOIN ciudades ci ON c.id_ciudad = ci.Id_ciudades
    LEFT JOIN sectores s ON c.sector = s.id_sector
    WHERE c.Id_cliente = p_socio;

    -- ============================================
    -- CONSULTA 3: Datos APR y fecha facturación (incluyendo datos para snapshot)
    -- ============================================
    SELECT 
        COALESCE(da.fecha_facturacion, '15'),
        COALESCE(da.porcentaje_multa, 0),
        COALESCE(da.tipo_multa, 0),
        COALESCE(da.Nombre_servicio, ''),
        COALESCE(da.rut_servicio, ''),
        COALESCE(da.Direccion, ''),
        COALESCE(co.nombre_comuna, ''),
        COALESCE(da.telefono_oficina, ''),
        COALESCE(da.Representante_legal, ''),
        COALESCE(da.fono_contacto, '')
    INTO 
        v_fecha_facturacion,
        v_porcentaje_multa,
        v_tipo_multa,
        v_apr_nombre,
        v_apr_rut,
        v_apr_direccion,
        v_apr_comuna,
        v_apr_telefono,
        v_apr_representante,
        v_apr_telefono_rep
    FROM datos_apr da
    LEFT JOIN comunas co ON da.Id_comunas = co.Id_comunas
    LIMIT 1;

    -- Calcular fecha vencimiento
    SET v_fecha_vencimiento = CONCAT(MID(DATE_ADD(NOW(), INTERVAL 1 MONTH), 1, 8), v_fecha_facturacion);

    -- ============================================
    -- CONSULTA 4: Fecha de lectura
    -- ============================================
    SELECT fecha_ingreso_lectura 
    INTO v_fecha_lectura
    FROM lecturas_clie_mensual 
    WHERE id_cliente = p_socio AND estado_pago = 0 
    LIMIT 1;

    -- ============================================
    -- CONSULTA 5: Multas del socio
    -- ============================================
    SELECT 
        COALESCE(multa_atraso, 0),
        COALESCE(multa_corte, 0),
        COALESCE(multa_matriz, 0)
    INTO 
        v_multa_atraso_flag,
        v_multa_corte_flag,
        v_multa_matriz_flag
    FROM multas_socio 
    WHERE Id_multas = p_socio;

    -- ============================================
    -- CONSULTA 6: Saldo anterior (deuda mes previo)
    -- ============================================
    SELECT COALESCE(monto, 0)
    INTO v_saldo_anterior
    FROM deudas 
    WHERE Id_cliente = p_socio 
      AND EXTRACT(YEAR_MONTH FROM fecha) = EXTRACT(YEAR_MONTH FROM DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) 
      AND estado_deuda = 5
    LIMIT 1;

    -- ============================================
    -- CONSULTA 7: Repactación activa
    -- ============================================
    SELECT 
        1,
        COALESCE(valor_cuota, 0),
        COALESCE(no_cuotas, 0),
        COALESCE(ult_cuota_facturada, 0)
    INTO 
        v_tiene_repactacion,
        v_valor_cuota,
        v_no_cuotas,
        v_ult_cuota_facturada
    FROM repactaciones 
    WHERE Id_cliente = p_socio AND estado_repactacion = 0
    LIMIT 1;

    -- ============================================
    -- CONSULTA 8: IDs de tipos de cargo (1 consulta, antes 11)
    -- ============================================
    SELECT 
        MAX(CASE WHEN codigo = 'CONSUMO_BASE' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'CONSUMO_TRAMO1' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'CARGO_FIJO' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'ALCANTARILLADO' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'CUOTA_MORTUORIA' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'MULTA_ATRASO' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'MULTA_CORTE' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'MULTA_MATRIZ' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'SUBSIDIO' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'REPACTACION' THEN id_tipo_cargo END),
        MAX(CASE WHEN codigo = 'SALDO_ANTERIOR' THEN id_tipo_cargo END)
    INTO 
        v_tc_consumo_base,
        v_tc_consumo_tramo1,
        v_tc_cargo_fijo,
        v_tc_alcantarillado,
        v_tc_mortuoria,
        v_tc_multa_atraso,
        v_tc_multa_corte,
        v_tc_multa_matriz,
        v_tc_subsidio,
        v_tc_repactacion,
        v_tc_saldo_anterior
    FROM tipos_cargo
    WHERE codigo IN ('CONSUMO_BASE', 'CONSUMO_TRAMO1', 'CARGO_FIJO', 'ALCANTARILLADO', 
                     'CUOTA_MORTUORIA', 'MULTA_ATRASO', 'MULTA_CORTE', 'MULTA_MATRIZ', 
                     'SUBSIDIO', 'REPACTACION', 'SALDO_ANTERIOR');

    -- ============================================
    -- CÁLCULO DE CONSUMO POR TRAMOS
    -- (Lógica 100% idéntica al original)
    -- ============================================
    IF v_inicio1 > 1 THEN
        -- Sistema con tramos configurados
        IF v_consumo_m3 > 0 THEN
            SET v_metraje_base = v_precio_metro3 * v_consumo_m3;
        END IF;

        IF v_inicio1 <= v_consumo_m3 THEN
            -- Hay sobreconsumo
            SET v_metraje_base = (v_inicio1 - 1) * v_precio_metro3;
            SET v_metraje_tramo1 = (v_consumo_m3 + 1 - v_inicio1) * v_sobreconsumo1;
        ELSE
            SET v_metraje_tramo1 = 0;
        END IF;

        SET v_consumo_total = v_metraje_base + v_metraje_tramo1 + v_metraje_tramo2 + v_metraje_tramo3;
    END IF;

    -- ============================================
    -- CÁLCULO DE CARGOS FIJOS
    -- ============================================
    SET v_cargo_fijo = v_cargo_fijo_caneria;
    SET v_alcantarillado_valor = v_alcantarillado;
    SET v_cargo_mortuoria = v_cuota_mortuoria_flag * v_valor_cuota_mortuoria;

    -- ============================================
    -- CÁLCULO DE SUBSIDIOS
    -- (Lógica 100% idéntica al original)
    -- ============================================
    SET v_subsidio_cargo_fijo = TRUNCATE((v_cargo_fijo_caneria * v_porcentaje_subsidio) / 100, 0);

    IF v_consumo_m3 <= v_limite_subsidio THEN
        SET v_subsidio_consumo = TRUNCATE((v_consumo_m3 * v_porcentaje_subsidio / 100) * v_precio_metro3, 0);
    ELSE
        SET v_subsidio_consumo = TRUNCATE((v_limite_subsidio * v_porcentaje_subsidio / 100) * v_precio_metro3, 0);
    END IF;

    SET v_subsidio_total = v_subsidio_cargo_fijo + v_subsidio_consumo;

    -- ============================================
    -- CÁLCULO DE TOTAL MES ACTUAL
    -- (Lógica 100% idéntica al original)
    -- ============================================
    IF v_inicio1 > 1 THEN
        SET v_total_mes_actual = (v_consumo_total - v_subsidio_consumo) 
                                + v_alcantarillado_valor 
                                + v_cargo_mortuoria 
                                + (v_cargo_fijo - v_subsidio_cargo_fijo);
    ELSE
        -- Sin tramos configurados
        SET v_total_mes_actual = TRUNCATE(
            (v_precio_metro3 * v_consumo_m3 - v_subsidio_consumo) 
            + v_alcantarillado_valor 
            + v_cargo_mortuoria 
            + (v_cargo_fijo_caneria - (v_cargo_fijo_caneria * v_porcentaje_subsidio / 100)), 0);
    END IF;

    -- ============================================
    -- CÁLCULO DE MULTAS
    -- (Lógica 100% idéntica al original)
    -- ============================================
    IF v_tipo_multa = 0 THEN
        -- Multa fija
        SET v_multa_atraso_valor = v_multa_atraso_tarifa * v_multa_atraso_flag;
        SET v_multa_corte_valor = v_corte_reposicion * v_multa_corte_flag;
        SET v_multa_matriz_valor = v_corte_matriz * v_multa_matriz_flag;
    ELSE
        -- Multa porcentual sobre saldo anterior
        SET v_multa_atraso_valor = TRUNCATE((v_saldo_anterior * v_porcentaje_multa / 100), 0) * v_multa_atraso_flag;
        SET v_multa_corte_valor = v_corte_reposicion * v_multa_corte_flag;
        SET v_multa_matriz_valor = v_corte_matriz * v_multa_matriz_flag;
    END IF;

    -- Sumar multa de atraso al total
    SET v_total_mes_actual = v_total_mes_actual + v_multa_atraso_valor;

    -- ============================================
    -- CÁLCULO DE TOTAL BOLETA
    -- ============================================
    SET v_total_boleta = v_total_mes_actual + v_saldo_anterior;

    -- ============================================
    -- APLICAR IMPUESTO SI CORRESPONDE
    -- ============================================
    SELECT COALESCE(impuesto, 0) INTO v_impuesto
    FROM tipo_documento 
    WHERE Id_doc = v_id_tipo_documento;

    IF v_impuesto > 0 THEN
        SET v_total_mes_actual = v_total_mes_actual + (v_total_mes_actual * v_impuesto / 100);
    END IF;

    -- ============================================
    -- OBTENER PRÓXIMO ID DE BOLETA
    -- ============================================
    SELECT AUTO_INCREMENT INTO v_prox_id_boleta 
    FROM information_schema.TABLES 
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'boletas';

    -- ============================================
    -- ACTUALIZAR LECTURA
    -- ============================================
    UPDATE lecturas_clie_mensual 
    SET id_boleta = v_prox_id_boleta 
    WHERE id_cliente = p_socio AND estado_pago = 0;

    -- ============================================
    -- PROCESAR REPACTACIÓN
    -- (Lógica 100% idéntica al original)
    -- ============================================
    IF v_tiene_repactacion = 1 THEN
        IF v_ult_cuota_facturada + 1 = v_no_cuotas THEN
            -- Última cuota
            UPDATE repactaciones 
            SET ult_cuota_facturada = v_no_cuotas, estado_repactacion = 1 
            WHERE Id_cliente = p_socio AND estado_repactacion = 0;
        ELSE
            UPDATE repactaciones 
            SET ult_cuota_facturada = ult_cuota_facturada + 1 
            WHERE Id_cliente = p_socio AND estado_repactacion = 0;
        END IF;
    ELSE
        SET v_valor_cuota = 0;
    END IF;

    -- ============================================
    -- INSERT EN DEUDAS
    -- ============================================
    INSERT INTO deudas (
        Id_cliente, Id_boleta, fecha, monto, respaldo_monto, 
        estado_deuda, saldo, respaldo_saldo, estado_saldo
    ) VALUES (
        p_socio, v_prox_id_boleta, CURDATE(), v_total_boleta, 0, 
        5, v_saldo_anterior, 0, 5
    );

    -- ============================================
    -- INSERT EN BOLETAS (mantiene compatibilidad)
    -- ============================================
    INSERT INTO boletas (
        num_boleta, id_cliente, tipo_de_docto, fecha_a_pagar, fecha_vencimiento, 
        lectura_ant_m3, lectura_act_m3, cosumo_m3, total_mes_act, cargo_fijo, 
        alcantarillado, subsidio, consumo, saldo_anterior, total_boleta, estado_pago, 
        cuota_mortuoria, donaciones, multa_atraso, tramo_base, tramo1, tramo2, tramo3, 
        subsidio1, subsidio2, subsidio3, subsidio4, subsidio5, repactacion, 
        fecha_toma_lectura, num_medidor, repactaciones,
        -- Datos APR (columnas obligatorias)
        nombre_servicio, rut_servicio, direccion_servicio, comuna_servicio,
        fono_oficina_servicio, rep_legal_servicio, fono_contacto_rep_legal,
        -- Datos Cliente (columnas obligatorias)
        nombre, rut, direccion, ciudad
    ) VALUES (
        0, p_socio, v_id_tipo_documento, CURDATE(), v_fecha_vencimiento, 
        p_lant, p_lact, v_consumo_m3, v_total_mes_actual, v_cargo_fijo, 
        v_alcantarillado_valor, v_subsidio_total, v_consumo_total, v_saldo_anterior, v_total_boleta, 5, 
        v_cargo_mortuoria, 0, v_multa_atraso_valor, v_metraje_base, v_metraje_tramo1, v_metraje_tramo2, v_metraje_tramo3, 
        v_subsidio_consumo, 0, 0, 0, 0, 0, 
        v_fecha_lectura, v_numero_medidor, v_valor_cuota,
        -- Valores APR
        v_apr_nombre, v_apr_rut, v_apr_direccion, v_apr_comuna,
        v_apr_telefono, v_apr_representante, v_apr_telefono_rep,
        -- Valores Cliente
        v_cliente_nombre, v_cliente_rut, v_cliente_direccion, v_cliente_ciudad
    );

    -- ============================================
    -- INSERT EN BOLETAS_DETALLE
    -- (Inserts condicionales - compatible MySQL 5.6)
    -- ============================================
    
    -- Consumo base
    IF v_metraje_base > 0 AND v_tc_consumo_base IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_consumo_base, LEAST(v_consumo_m3, v_inicio1 - 1), v_precio_metro3, v_metraje_base);
    END IF;
    
    -- Consumo tramo 1
    IF v_metraje_tramo1 > 0 AND v_tc_consumo_tramo1 IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_consumo_tramo1, v_consumo_m3 + 1 - v_inicio1, v_sobreconsumo1, v_metraje_tramo1);
    END IF;
    
    -- Cargo fijo
    IF v_cargo_fijo > 0 AND v_tc_cargo_fijo IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_cargo_fijo, 1, v_cargo_fijo, v_cargo_fijo);
    END IF;
    
    -- Alcantarillado
    IF v_alcantarillado_valor > 0 AND v_tc_alcantarillado IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_alcantarillado, 1, v_alcantarillado_valor, v_alcantarillado_valor);
    END IF;
    
    -- Cuota mortuoria
    IF v_cargo_mortuoria > 0 AND v_tc_mortuoria IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_mortuoria, 1, v_cargo_mortuoria, v_cargo_mortuoria);
    END IF;
    
    -- Multa atraso
    IF v_multa_atraso_valor > 0 AND v_tc_multa_atraso IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_multa_atraso, 1, v_multa_atraso_valor, v_multa_atraso_valor);
    END IF;
    
    -- Multa corte
    IF v_multa_corte_valor > 0 AND v_tc_multa_corte IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_multa_corte, 1, v_multa_corte_valor, v_multa_corte_valor);
    END IF;
    
    -- Multa matriz
    IF v_multa_matriz_valor > 0 AND v_tc_multa_matriz IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_multa_matriz, 1, v_multa_matriz_valor, v_multa_matriz_valor);
    END IF;
    
    -- Subsidio
    IF v_subsidio_total > 0 AND v_tc_subsidio IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_subsidio, 1, v_subsidio_total, v_subsidio_total);
    END IF;
    
    -- Repactación
    IF v_valor_cuota > 0 AND v_tc_repactacion IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_repactacion, 1, v_valor_cuota, v_valor_cuota);
    END IF;
    
    -- Saldo anterior
    IF v_saldo_anterior > 0 AND v_tc_saldo_anterior IS NOT NULL THEN
        INSERT INTO boletas_detalle (id_boleta, id_tipo_cargo, cantidad, valor_unitario, monto)
        VALUES (v_prox_id_boleta, v_tc_saldo_anterior, 1, v_saldo_anterior, v_saldo_anterior);
    END IF;

    -- NUEVO: Guardar snapshot histórico (CONCAT para MySQL 5.6)
    INSERT INTO boletas_snapshot (id_boleta, snapshot_datos, fecha_creacion)
    VALUES (
        v_prox_id_boleta,
        CONCAT(
            '{"datos_cliente":{"nombre":"', REPLACE(IFNULL(v_cliente_nombre, ''), '"', '\\"'), '",',
            '"rut":"', IFNULL(v_cliente_rut, ''), '",',
            '"direccion":"', REPLACE(IFNULL(v_cliente_direccion, ''), '"', '\\"'), '",',
            '"ciudad":"', REPLACE(IFNULL(v_cliente_ciudad, 'Sin especificar'), '"', '\\"'), '",',
            '"sector":"', REPLACE(IFNULL(v_cliente_sector, ''), '"', '\\"'), '",',
            '"numero_medidor":"', IFNULL(v_numero_medidor, '0'), '"},',
            '"datos_apr":{"nombre_servicio":"', REPLACE(IFNULL(v_apr_nombre, ''), '"', '\\"'), '",',
            '"rut_servicio":"', IFNULL(v_apr_rut, ''), '",',
            '"direccion_servicio":"', REPLACE(IFNULL(v_apr_direccion, ''), '"', '\\"'), '",',
            '"comuna_servicio":"', REPLACE(IFNULL(v_apr_comuna, ''), '"', '\\"'), '",',
            '"telefono_oficina":"', IFNULL(v_apr_telefono, ''), '",',
            '"representante_legal":"', REPLACE(IFNULL(v_apr_representante, ''), '"', '\\"'), '",',
            '"telefono_representante":"', IFNULL(v_apr_telefono_rep, ''), '"},',
            '"datos_boleta":{"num_boleta":0,',
            '"fecha_emision":"', CURDATE(), '",',
            '"fecha_vencimiento":"', IFNULL(v_fecha_vencimiento, ''), '",',
            '"total_boleta":', IFNULL(v_total_boleta, 0), ',',
            '"estado_pago":5,',
            '"lectura_anterior":', IFNULL(p_lant, 0), ',',
            '"lectura_actual":', IFNULL(p_lact, 0), ',',
            '"consumo_m3":', IFNULL(v_consumo_m3, 0), '}}'
        ),
        CURDATE()
    );

    -- ============================================
    -- ACTUALIZAR ESTADO DEL SOCIO
    -- ============================================
    IF v_estado_socio < 3 THEN
        UPDATE clientes 
        SET estado_socio = estado_socio + 1 
        WHERE Id_cliente = p_socio;
    END IF;
    
    COMMIT;
END //

DELIMITER ;

-- ============================================
-- VERIFICACIÓN
-- ============================================
-- Comparar resultados antes y después:
-- 
-- ANTES (procedimiento anterior):
-- SELECT * FROM boletas WHERE id_cliente = 1 ORDER BY id_boleta DESC LIMIT 1;
-- 
-- DESPUÉS (procedimiento optimizado):
-- CALL calulo_boleta(1, 100, 125);
-- SELECT * FROM boletas WHERE id_cliente = 1 ORDER BY id_boleta DESC LIMIT 1;
-- SELECT * FROM vista_boletas_detalle WHERE id_boleta = (SELECT MAX(id_boleta) FROM boletas);
--
-- Los valores deben ser IDÉNTICOS
