-- ============================================================================
-- Archivo: 01-init-database.sql
-- Descripcion: Inicializacion completa de base de datos - Carga Limpia
-- Proyecto: ERP Suite - Vertical Construccion
-- Version: 2.0.0
-- Fecha: 2025-12-06
-- ============================================================================
-- POLITICA: CARGA LIMPIA (ver DIRECTIVA-POLITICA-CARGA-LIMPIA.md)
-- Este archivo es parte de la fuente de verdad DDL.
-- NO usar migrations, fixes o patches incrementales.
-- ============================================================================

-- ============================================================================
-- EXTENSIONES
-- ============================================================================

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";      -- Generacion de UUIDs
CREATE EXTENSION IF NOT EXISTS "pgcrypto";       -- Funciones criptograficas
CREATE EXTENSION IF NOT EXISTS "postgis";        -- Geolocalizacion
CREATE EXTENSION IF NOT EXISTS "pg_trgm";        -- Busqueda fuzzy
CREATE EXTENSION IF NOT EXISTS "btree_gist";     -- Indices GiST avanzados

-- ============================================================================
-- SCHEMA: core_shared (funciones compartidas)
-- ============================================================================

CREATE SCHEMA IF NOT EXISTS core_shared;

COMMENT ON SCHEMA core_shared IS 'Funciones, tipos y utilidades compartidas entre modulos';

-- ============================================================================
-- FUNCIONES DE AUDITORIA
-- ============================================================================

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

COMMENT ON FUNCTION core_shared.set_updated_at() IS
'Trigger function para actualizar automaticamente el campo updated_at en cada UPDATE';

-- Funcion para establecer tenant_id desde contexto
CREATE OR REPLACE FUNCTION core_shared.set_tenant_id()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.tenant_id IS NULL THEN
        NEW.tenant_id = current_setting('app.current_tenant_id', true)::uuid;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION core_shared.set_tenant_id() IS
'Trigger function para establecer tenant_id automaticamente desde el contexto de sesion';

-- Funcion para establecer created_by desde contexto
CREATE OR REPLACE FUNCTION core_shared.set_created_by()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.created_by IS NULL THEN
        NEW.created_by = current_setting('app.current_user_id', true)::uuid;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION core_shared.set_created_by() IS
'Trigger function para establecer created_by automaticamente desde el contexto de sesion';

-- ============================================================================
-- FUNCIONES DE CONTEXTO
-- ============================================================================

CREATE OR REPLACE FUNCTION core_shared.get_current_tenant_id()
RETURNS UUID AS $$
BEGIN
    RETURN NULLIF(current_setting('app.current_tenant_id', true), '')::UUID;
EXCEPTION
    WHEN OTHERS THEN
        RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION core_shared.get_current_tenant_id() IS
'Obtiene el ID del tenant actual desde el contexto de sesion';

CREATE OR REPLACE FUNCTION core_shared.get_current_user_id()
RETURNS UUID AS $$
BEGIN
    RETURN NULLIF(current_setting('app.current_user_id', true), '')::UUID;
EXCEPTION
    WHEN OTHERS THEN
        RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION core_shared.get_current_user_id() IS
'Obtiene el ID del usuario actual desde el contexto de sesion';

-- ============================================================================
-- FUNCIONES DE UTILIDAD
-- ============================================================================

-- Generar slug desde texto
CREATE OR REPLACE FUNCTION core_shared.generate_slug(input_text TEXT)
RETURNS TEXT AS $$
BEGIN
    RETURN LOWER(
        REGEXP_REPLACE(
            REGEXP_REPLACE(
                TRIM(input_text),
                '[^a-zA-Z0-9\s-]', '', 'g'
            ),
            '\s+', '-', 'g'
        )
    );
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- Validar formato de email
CREATE OR REPLACE FUNCTION core_shared.is_valid_email(email TEXT)
RETURNS BOOLEAN AS $$
BEGIN
    RETURN email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$';
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- Validar formato de RFC mexicano
CREATE OR REPLACE FUNCTION core_shared.is_valid_rfc(rfc TEXT)
RETURNS BOOLEAN AS $$
BEGIN
    RETURN rfc ~* '^[A-Z&Ñ]{3,4}[0-9]{6}[A-Z0-9]{3}$';
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- ============================================================================
-- PERMISOS
-- ============================================================================

GRANT USAGE ON SCHEMA core_shared TO PUBLIC;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA core_shared TO PUBLIC;

-- ============================================================================
-- SCHEMAS DE NEGOCIO - NOMENCLATURA UNIFICADA
-- ============================================================================
-- Segun NAMING-CONVENTIONS.md, usamos nombres cortos y descriptivos:
--   - construction (antes project_management, construction_management)
--   - estimates (antes financial_management)
--   - infonavit (antes infonavit_management)
--   - hr (extension de erp-core)
--   - inventory (extension de erp-core)
--   - purchase (extension de erp-core)
--   - hse (nuevo: seguridad, salud, medio ambiente)
-- ============================================================================

-- Schemas propios de construccion
CREATE SCHEMA IF NOT EXISTS construction;
CREATE SCHEMA IF NOT EXISTS estimates;
CREATE SCHEMA IF NOT EXISTS infonavit;
CREATE SCHEMA IF NOT EXISTS hse;

-- Schemas de extension (extendemos modulos de erp-core)
-- Estos pueden ya existir si erp-core esta instalado
CREATE SCHEMA IF NOT EXISTS hr;
CREATE SCHEMA IF NOT EXISTS inventory;
CREATE SCHEMA IF NOT EXISTS purchase;

-- Schemas legacy (compatibilidad temporal, marcar para deprecacion)
-- NOTA: Estos seran eliminados en version futura
CREATE SCHEMA IF NOT EXISTS auth_management;
CREATE SCHEMA IF NOT EXISTS project_management;
CREATE SCHEMA IF NOT EXISTS financial_management;
CREATE SCHEMA IF NOT EXISTS purchasing_management;
CREATE SCHEMA IF NOT EXISTS inventory_management;
CREATE SCHEMA IF NOT EXISTS construction_management;
CREATE SCHEMA IF NOT EXISTS quality_management;
CREATE SCHEMA IF NOT EXISTS safety_management;
CREATE SCHEMA IF NOT EXISTS infonavit_management;

-- ============================================================================
-- COMENTARIOS EN SCHEMAS
-- ============================================================================

-- Schemas principales (nuevos)
COMMENT ON SCHEMA construction IS
    'Gestion de obras: proyectos, fraccionamientos, fases, viviendas, avances';

COMMENT ON SCHEMA estimates IS
    'Presupuestos, partidas, estimaciones, control de costos';

COMMENT ON SCHEMA infonavit IS
    'Integracion INFONAVIT: tramites, ECUVE, subsidios, normatividad';

COMMENT ON SCHEMA hse IS
    'Seguridad, Salud Ocupacional y Medio Ambiente (HSE/EHS)';

COMMENT ON SCHEMA hr IS
    'Extension de RRHH para construccion: cuadrillas, destajo, asistencia obra';

COMMENT ON SCHEMA inventory IS
    'Extension de inventarios: almacenes de obra, control de materiales';

COMMENT ON SCHEMA purchase IS
    'Extension de compras: proveedores de construccion, requisiciones de obra';

-- Schemas legacy (deprecated)
COMMENT ON SCHEMA auth_management IS
    'DEPRECATED: Usar core.auth. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA project_management IS
    'DEPRECATED: Usar construction. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA financial_management IS
    'DEPRECATED: Usar estimates. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA purchasing_management IS
    'DEPRECATED: Usar purchase. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA inventory_management IS
    'DEPRECATED: Usar inventory. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA construction_management IS
    'DEPRECATED: Usar construction. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA quality_management IS
    'DEPRECATED: Funcionalidad movida a hse (inspecciones) y construction (calidad)';

COMMENT ON SCHEMA safety_management IS
    'DEPRECATED: Usar hse. Schema mantenido para compatibilidad';

COMMENT ON SCHEMA infonavit_management IS
    'DEPRECATED: Usar infonavit. Schema mantenido para compatibilidad';

-- ============================================================================
-- FUNCION LEGACY (compatibilidad)
-- ============================================================================

CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = now();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION update_updated_at_column() IS
    'LEGACY: Usar core_shared.set_updated_at() en nuevas tablas';

-- ============================================================================
-- TABLAS CORE MINIMAS (si erp-core no esta instalado)
-- ============================================================================
-- Estas tablas son requeridas como FK por los modulos de construccion
-- Si erp-core esta instalado, estas ya existiran y el IF NOT EXISTS las omitira

-- Schema core para tablas compartidas
CREATE SCHEMA IF NOT EXISTS core;

-- Tabla de tenants (multi-tenancy)
CREATE TABLE IF NOT EXISTS core.tenants (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    code VARCHAR(50) NOT NULL UNIQUE,
    name VARCHAR(200) NOT NULL,
    is_active BOOLEAN NOT NULL DEFAULT true,
    settings JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Tabla de usuarios
CREATE TABLE IF NOT EXISTS core.users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID REFERENCES core.tenants(id),
    email VARCHAR(255) NOT NULL,
    username VARCHAR(100),
    is_active BOOLEAN NOT NULL DEFAULT true,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE(tenant_id, email)
);

-- ============================================================================
-- VERIFICACION
-- ============================================================================

DO $$
DECLARE
    schema_count INTEGER;
    ext_count INTEGER;
BEGIN
    SELECT COUNT(*) INTO schema_count
    FROM pg_namespace
    WHERE nspname IN ('construction', 'estimates', 'infonavit', 'hse', 'hr', 'inventory', 'purchase', 'core', 'core_shared');

    SELECT COUNT(*) INTO ext_count
    FROM pg_extension
    WHERE extname IN ('uuid-ossp', 'pgcrypto', 'postgis', 'pg_trgm', 'btree_gist');

    RAISE NOTICE '============================================================';
    RAISE NOTICE 'ERP CONSTRUCCION - Base de datos inicializada';
    RAISE NOTICE '============================================================';
    RAISE NOTICE 'Extensiones instaladas: %', ext_count;
    RAISE NOTICE 'Schemas principales creados: %', schema_count;
    RAISE NOTICE '============================================================';
    RAISE NOTICE 'Schemas principales: construction, estimates, infonavit, hse';
    RAISE NOTICE 'Schemas extension: hr, inventory, purchase';
    RAISE NOTICE 'Schemas compartidos: core, core_shared';
    RAISE NOTICE '============================================================';
END $$;

-- ============================================================================
-- FIN
-- ============================================================================
