-- =============================================================================
-- Horux Strategy - Script de Inicializacion PostgreSQL
-- =============================================================================
-- Este script se ejecuta automaticamente cuando el contenedor de PostgreSQL
-- se inicia por primera vez.
--
-- Crea:
--   - Base de datos horux_strategy
--   - Usuario de aplicacion con permisos limitados
--   - Extensiones necesarias
--   - Esquemas base
-- =============================================================================

-- Crear base de datos si no existe (la variable POSTGRES_DB ya la crea)
-- Este bloque es por si se necesita una base de datos adicional
-- CREATE DATABASE horux_strategy_test;

-- =============================================================================
-- Extensiones necesarias
-- =============================================================================

-- UUID: Generacion de identificadores unicos universales
-- Usado para IDs de entidades (usuarios, empresas, transacciones, etc.)
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- pgcrypto: Funciones criptograficas
-- Usado para hash de passwords, generacion de tokens seguros
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- pg_trgm: Busqueda por trigramas
-- Mejora las busquedas de texto parcial (LIKE, ILIKE)
CREATE EXTENSION IF NOT EXISTS "pg_trgm";

-- btree_gin: Indices GIN para tipos de datos adicionales
-- Mejora consultas con multiples condiciones en indices compuestos
CREATE EXTENSION IF NOT EXISTS "btree_gin";

-- =============================================================================
-- Usuario de aplicacion
-- =============================================================================
-- Creamos un usuario con permisos limitados para la aplicacion
-- Esto sigue el principio de menor privilegio

DO $$
BEGIN
    -- Crear usuario de aplicacion si no existe
    IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'horux_app') THEN
        CREATE USER horux_app WITH PASSWORD 'horux_app_secret';
    END IF;
END
$$;

-- Permisos en la base de datos
GRANT CONNECT ON DATABASE horux_strategy TO horux_app;

-- Permisos en el esquema public
GRANT USAGE ON SCHEMA public TO horux_app;
GRANT CREATE ON SCHEMA public TO horux_app;

-- Permisos por defecto para tablas futuras
ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO horux_app;

-- Permisos por defecto para secuencias futuras
ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT USAGE, SELECT ON SEQUENCES TO horux_app;

-- =============================================================================
-- Esquemas adicionales (opcional)
-- =============================================================================

-- Esquema para datos de auditoria
CREATE SCHEMA IF NOT EXISTS audit;
GRANT USAGE ON SCHEMA audit TO horux_app;
GRANT CREATE ON SCHEMA audit TO horux_app;
ALTER DEFAULT PRIVILEGES IN SCHEMA audit
    GRANT SELECT, INSERT ON TABLES TO horux_app;

-- Esquema para reportes y vistas materializadas
CREATE SCHEMA IF NOT EXISTS reports;
GRANT USAGE ON SCHEMA reports TO horux_app;
ALTER DEFAULT PRIVILEGES IN SCHEMA reports
    GRANT SELECT ON TABLES TO horux_app;

-- =============================================================================
-- Funciones de utilidad
-- =============================================================================

-- Funcion para generar UUIDs v4
CREATE OR REPLACE FUNCTION generate_uuid()
RETURNS UUID AS $$
BEGIN
    RETURN uuid_generate_v4();
END;
$$ LANGUAGE plpgsql;

-- Funcion para actualizar timestamps automaticamente
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Funcion para registrar cambios en auditoria
CREATE OR REPLACE FUNCTION audit.log_changes()
RETURNS TRIGGER AS $$
DECLARE
    audit_table_name TEXT;
BEGIN
    audit_table_name := TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME || '_audit';

    IF TG_OP = 'DELETE' THEN
        EXECUTE format(
            'INSERT INTO audit.changes_log (table_name, operation, old_data, changed_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP)'
        ) USING TG_TABLE_NAME, TG_OP, row_to_json(OLD);
        RETURN OLD;
    ELSIF TG_OP = 'UPDATE' THEN
        EXECUTE format(
            'INSERT INTO audit.changes_log (table_name, operation, old_data, new_data, changed_at) VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP)'
        ) USING TG_TABLE_NAME, TG_OP, row_to_json(OLD), row_to_json(NEW);
        RETURN NEW;
    ELSIF TG_OP = 'INSERT' THEN
        EXECUTE format(
            'INSERT INTO audit.changes_log (table_name, operation, new_data, changed_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP)'
        ) USING TG_TABLE_NAME, TG_OP, row_to_json(NEW);
        RETURN NEW;
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

-- Tabla para log de cambios de auditoria
CREATE TABLE IF NOT EXISTS audit.changes_log (
    id BIGSERIAL PRIMARY KEY,
    table_name VARCHAR(100) NOT NULL,
    operation VARCHAR(10) NOT NULL,
    old_data JSONB,
    new_data JSONB,
    changed_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    changed_by UUID  -- Se puede llenar con el usuario de la sesion
);

-- Indice para busquedas rapidas por tabla y fecha
CREATE INDEX IF NOT EXISTS idx_audit_changes_table_date
    ON audit.changes_log (table_name, changed_at DESC);

-- =============================================================================
-- Mensaje de confirmacion
-- =============================================================================
DO $$
BEGIN
    RAISE NOTICE '===========================================';
    RAISE NOTICE 'Horux Strategy - Base de datos inicializada';
    RAISE NOTICE '===========================================';
    RAISE NOTICE 'Extensiones instaladas:';
    RAISE NOTICE '  - uuid-ossp';
    RAISE NOTICE '  - pgcrypto';
    RAISE NOTICE '  - pg_trgm';
    RAISE NOTICE '  - btree_gin';
    RAISE NOTICE 'Usuarios creados:';
    RAISE NOTICE '  - horux_app (usuario de aplicacion)';
    RAISE NOTICE 'Esquemas creados:';
    RAISE NOTICE '  - public (tablas principales)';
    RAISE NOTICE '  - audit (auditoria de cambios)';
    RAISE NOTICE '  - reports (reportes y vistas)';
    RAISE NOTICE '===========================================';
END
$$;
