-- =============================================
-- Author:      System
-- Create date: 2025-12-31
-- Description: Stored Procedures for Financial Reports
-- =============================================

-- 1. Reporte de Movimientos Detallado
CREATE OR REPLACE FUNCTION sp_reporte_movimientos(p_fecha_inicio DATE, p_fecha_fin DATE)
RETURNS TABLE (
    id BIGINT,
    fecha DATE,
    tipo_movimiento VARCHAR,
    concepto TEXT,
    categoria VARCHAR,
    monto DECIMAL(12,2),
    usuario VARCHAR
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        m.id,
        m.fecha_movimiento,
        m.tipo_movimiento::VARCHAR,
        m.descripcion::TEXT as concepto,
        COALESCE(c.nombre, 'General')::VARCHAR as categoria,
        m.monto,
        COALESCE(p.nombres || ' ' || p.apellidos, 'Sistema')::VARCHAR as usuario
    FROM caja_chica_movimientos m
    LEFT JOIN categorias_gastos c ON m.categoria_gasto_id = c.id
    LEFT JOIN usuarios u ON m.usuario_registro_id = u.id
    LEFT JOIN personas p ON u.persona_id = p.id
    WHERE m.fecha_movimiento BETWEEN p_fecha_inicio AND p_fecha_fin
    ORDER BY m.fecha_movimiento DESC, m.creado_en DESC;
END;
$$ LANGUAGE plpgsql;

-- 2. Reporte de Gastos por Categoría
CREATE OR REPLACE FUNCTION sp_reporte_gastos_categoria(p_fecha_inicio DATE, p_fecha_fin DATE)
RETURNS TABLE (
    categoria VARCHAR,
    cantidad BIGINT,
    monto_total DECIMAL(12,2)
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        COALESCE(c.nombre, 'Sin Categoría')::VARCHAR as categoria,
        COUNT(*) as cantidad,
        SUM(m.monto) as monto_total
    FROM caja_chica_movimientos m
    LEFT JOIN categorias_gastos c ON m.categoria_gasto_id = c.id
    WHERE m.fecha_movimiento BETWEEN p_fecha_inicio AND p_fecha_fin
      AND m.tipo_movimiento IN ('GASTO', 'DISMINUCION_FONDO')
    GROUP BY COALESCE(c.nombre, 'Sin Categoría')
    ORDER BY monto_total DESC;
END;
$$ LANGUAGE plpgsql;

-- 3. Reporte de Reposiciones
CREATE OR REPLACE FUNCTION sp_reporte_reposiciones(p_fecha_inicio DATE, p_fecha_fin DATE)
RETURNS TABLE (
    fecha DATE,
    monto DECIMAL(12,2),
    usuario VARCHAR,
    descripcion TEXT
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        m.fecha_movimiento,
        m.monto,
        COALESCE(p.nombres || ' ' || p.apellidos, 'Sistema')::VARCHAR as usuario,
        m.descripcion::TEXT
    FROM caja_chica_movimientos m
    LEFT JOIN usuarios u ON m.usuario_registro_id = u.id
    LEFT JOIN personas p ON u.persona_id = p.id
    WHERE m.fecha_movimiento BETWEEN p_fecha_inicio AND p_fecha_fin
      AND m.tipo_movimiento IN ('REPOSICION', 'AUMENTO_FONDO', 'APERTURA')
    ORDER BY m.fecha_movimiento DESC;
END;
$$ LANGUAGE plpgsql;

-- 4. Histórico de Saldos (Complejo: Requiere calcular saldo día a día)
-- Nota: Esto puede ser lento en rangos grandes. Para producción real se recomienda una tabla de snapshots diarios.
-- Aquí usaremos una aproximación calculando el saldo acumulado.

CREATE OR REPLACE FUNCTION sp_reporte_historico_saldos(p_fecha_inicio DATE, p_fecha_fin DATE)
RETURNS TABLE (
    fecha DATE,
    saldo_inicial DECIMAL(12,2),
    ingresos DECIMAL(12,2),
    egresos DECIMAL(12,2),
    saldo_final DECIMAL(12,2)
) AS $$
DECLARE
    r RECORD;
    v_saldo_acumulado DECIMAL(12,2) := 0;
    v_fecha_iteracion DATE;
BEGIN
    -- 1. Calcular saldo inicial antes del periodo
    SELECT COALESCE(SUM(
        CASE 
            WHEN tipo_movimiento IN ('APERTURA', 'REPOSICION', 'AUMENTO_FONDO') THEN monto 
            WHEN tipo_movimiento IN ('GASTO', 'DISMINUCION_FONDO') THEN -monto
            ELSE 0 
        END), 0)
    INTO v_saldo_acumulado
    FROM caja_chica_movimientos
    WHERE fecha_movimiento < p_fecha_inicio;

    -- 2. Iterar por cada día del rango (o solo días con movimientos si se prefiere, aquí haremos todos los días)
    -- Generar serie de fechas
    FOR v_fecha_iteracion IN SELECT generate_series(p_fecha_inicio, p_fecha_fin, '1 day'::interval)::date
    LOOP
        -- Calcular movimientos del día
        SELECT 
            COALESCE(SUM(CASE WHEN tipo_movimiento IN ('APERTURA', 'REPOSICION', 'AUMENTO_FONDO') THEN monto ELSE 0 END), 0),
            COALESCE(SUM(CASE WHEN tipo_movimiento IN ('GASTO', 'DISMINUCION_FONDO') THEN monto ELSE 0 END), 0)
        INTO ingresos, egresos
        FROM caja_chica_movimientos
        WHERE fecha_movimiento = v_fecha_iteracion;

        -- Asignar valores
        fecha := v_fecha_iteracion;
        saldo_inicial := v_saldo_acumulado;
        saldo_final := saldo_inicial + ingresos - egresos;
        
        -- Actualizar acumulado para el siguiente día
        v_saldo_acumulado := saldo_final;

        RETURN NEXT;
    END LOOP;
END;
$$ LANGUAGE plpgsql;
