-- =====================================================
-- Script SQL para Sistema de Contabilidad General
-- Base de datos: PostgreSQL
-- Fecha: 2026-01-28
-- =====================================================

-- =====================================================
-- 1. CREAR TABLAS
-- =====================================================

-- Tabla: categorias_ingreso
CREATE TABLE IF NOT EXISTS public.categorias_ingreso
(
    id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    nombre character varying(100) COLLATE pg_catalog."default" NOT NULL,
    descripcion character varying(255) COLLATE pg_catalog."default",
    activa boolean NOT NULL DEFAULT true,
    fecha_creacion timestamp without time zone NOT NULL DEFAULT (NOW() AT TIME ZONE 'UTC'),
    CONSTRAINT pk_categorias_ingreso PRIMARY KEY (id)
);

-- Tabla: categorias_egreso
CREATE TABLE IF NOT EXISTS public.categorias_egreso
(
    id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    nombre character varying(100) COLLATE pg_catalog."default" NOT NULL,
    descripcion character varying(255) COLLATE pg_catalog."default",
    activa boolean NOT NULL DEFAULT true,
    fecha_creacion timestamp without time zone NOT NULL DEFAULT (NOW() AT TIME ZONE 'UTC'),
    CONSTRAINT pk_categorias_egreso PRIMARY KEY (id)
);

-- Tabla: reportes_mensuales_generales
CREATE TABLE IF NOT EXISTS public.reportes_mensuales_generales
(
    id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    mes integer NOT NULL,
    anio integer NOT NULL,
    saldo_inicial numeric(18,2) NOT NULL DEFAULT 0,
    fecha_creacion timestamp without time zone NOT NULL DEFAULT (NOW() AT TIME ZONE 'UTC'),
    cerrado boolean NOT NULL DEFAULT false,
    CONSTRAINT pk_reportes_mensuales_generales PRIMARY KEY (id),
    CONSTRAINT uk_mes_anio_general UNIQUE (mes, anio),
    CONSTRAINT ck_mes_rango CHECK (mes >= 1 AND mes <= 12),
    CONSTRAINT ck_anio_valido CHECK (anio >= 2000 AND anio <= 2100)
);

-- Crear tipo enum para tipo_movimiento_general si no existe
DO $$ BEGIN
    CREATE TYPE tipo_movimiento_general AS ENUM ('Ingreso', 'Egreso');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla: movimientos_generales
CREATE TABLE IF NOT EXISTS public.movimientos_generales
(
    id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    reporte_mensual_general_id bigint,
    tipo tipo_movimiento_general NOT NULL,
    categoria_ingreso_id bigint,
    categoria_egreso_id bigint,
    monto numeric(18,2) NOT NULL,
    fecha timestamp without time zone NOT NULL,
    descripcion character varying(200) COLLATE pg_catalog."default" NOT NULL DEFAULT '',
    numero_comprobante character varying(50) COLLATE pg_catalog."default",
    CONSTRAINT pk_movimientos_generales PRIMARY KEY (id),
    CONSTRAINT fk_movimientos_reporte FOREIGN KEY (reporte_mensual_general_id)
        REFERENCES public.reportes_mensuales_generales (id)
        ON DELETE CASCADE,
    CONSTRAINT fk_movimientos_categoria_ingreso FOREIGN KEY (categoria_ingreso_id)
        REFERENCES public.categorias_ingreso (id)
        ON DELETE RESTRICT,
    CONSTRAINT fk_movimientos_categoria_egreso FOREIGN KEY (categoria_egreso_id)
        REFERENCES public.categorias_egreso (id)
        ON DELETE RESTRICT,
    CONSTRAINT ck_monto_positivo CHECK (monto > 0),
    CONSTRAINT ck_categoria_tipo CHECK (
        (tipo = 'Ingreso' AND categoria_ingreso_id IS NOT NULL AND categoria_egreso_id IS NULL) OR
        (tipo = 'Egreso' AND categoria_egreso_id IS NOT NULL AND categoria_ingreso_id IS NULL)
    )
);

-- =====================================================
-- 2. CREAR ÍNDICES
-- =====================================================

CREATE INDEX IF NOT EXISTS idx_movimientos_reporte 
    ON public.movimientos_generales (reporte_mensual_general_id);

CREATE INDEX IF NOT EXISTS idx_movimientos_fecha 
    ON public.movimientos_generales (fecha);

CREATE INDEX IF NOT EXISTS idx_movimientos_categoria_ingreso 
    ON public.movimientos_generales (categoria_ingreso_id);

CREATE INDEX IF NOT EXISTS idx_movimientos_categoria_egreso 
    ON public.movimientos_generales (categoria_egreso_id);

CREATE INDEX IF NOT EXISTS idx_reportes_anio 
    ON public.reportes_mensuales_generales (anio);

-- =====================================================
-- 3. INSERTAR DATOS INICIALES - CATEGORÍAS DE INGRESO
-- =====================================================

INSERT INTO public.categorias_ingreso (nombre, descripcion, activa) VALUES
('Ofrendas', 'Ofrendas regulares de los cultos', true),
('Donaciones', 'Donaciones especiales de hermanos y visitantes', true),
('Diezmos', 'Diezmos de los miembros', true),
('Eventos Especiales', 'Ingresos de eventos, conferencias, retiros', true),
('Alquileres', 'Ingresos por alquiler de instalaciones', true),
('Ventas', 'Ventas de materiales, libros u otros productos', true),
('Otros Ingresos', 'Ingresos diversos no categorizados', true)
ON CONFLICT DO NOTHING;

-- =====================================================
-- 4. INSERTAR DATOS INICIALES - CATEGORÍAS DE EGRESO
-- =====================================================

INSERT INTO public.categorias_egreso (nombre, descripcion, activa) VALUES
('Agua', 'Pago del servicio de agua', true),
('Luz', 'Pago del servicio de electricidad', true),
('Teléfono/Internet', 'Servicios de telefonía e internet', true),
('Impuestos', 'Pago de impuestos municipales, prediales, etc.', true),
('Funeraria', 'Gastos relacionados con servicios funerarios', true),
('Mantenimiento Edificio', 'Reparaciones y mantenimiento de las instalaciones', true),
('Suministros Ministerio', 'Materiales para ministerios (niños, jóvenes, etc.)', true),
('Salarios Personal', 'Salarios de pastores y personal administrativo', true),
('Eventos', 'Gastos de organización de eventos', true),
('Transporte', 'Gastos de transporte y combustible', true),
('Limpieza', 'Servicios de limpieza y productos', true),
('Seguridad', 'Servicio de seguridad o vigilancia', true),
('Otros Gastos', 'Gastos diversos no categorizados', true)
ON CONFLICT DO NOTHING;

-- =====================================================
-- 5. COMENTARIOS SOBRE LAS TABLAS
-- =====================================================

COMMENT ON TABLE public.categorias_ingreso IS 'Categorías para clasificar los ingresos de la iglesia';
COMMENT ON TABLE public.categorias_egreso IS 'Categorías para clasificar los egresos de la iglesia';
COMMENT ON TABLE public.reportes_mensuales_generales IS 'Reportes mensuales de contabilidad general de la iglesia';
COMMENT ON TABLE public.movimientos_generales IS 'Movimientos individuales de ingresos y egresos';

-- =====================================================
-- 6. VERIFICACIÓN
-- =====================================================

-- Verificar que se crearon las tablas
SELECT 
    table_name,
    (SELECT COUNT(*) FROM information_schema.columns WHERE table_name = t.table_name) as columnas
FROM information_schema.tables t
WHERE table_schema = 'public' 
  AND table_name IN (
    'categorias_ingreso',
    'categorias_egreso',
    'reportes_mensuales_generales',
    'movimientos_generales'
  )
ORDER BY table_name;

-- Verificar datos iniciales de categorías
SELECT 'Categorías de Ingreso' as tipo, COUNT(*) as total FROM public.categorias_ingreso
UNION ALL
SELECT 'Categorías de Egreso' as tipo, COUNT(*) as total FROM public.categorias_egreso;

-- =====================================================
-- FIN DEL SCRIPT
-- =====================================================
