-- =============================================================
-- ARCHIVO: 07-users-rbac.sql
-- DESCRIPCION: Sistema RBAC (Roles, Permisos, Invitaciones)
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core V2
-- FECHA: 2026-01-10
-- EPIC: SAAS-CORE-AUTH (EPIC-SAAS-001)
-- HISTORIAS: US-004, US-005, US-006, US-030
-- =============================================================

-- =====================
-- SCHEMA: users
-- =====================
CREATE SCHEMA IF NOT EXISTS users;

-- =====================
-- TABLA: users.roles
-- Roles del sistema con herencia (US-004)
-- =====================
CREATE TABLE IF NOT EXISTS users.roles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Info basica
    name VARCHAR(100) NOT NULL,
    display_name VARCHAR(255),
    description TEXT,
    color VARCHAR(20),
    icon VARCHAR(50),

    -- Jerarquia
    parent_role_id UUID REFERENCES users.roles(id) ON DELETE SET NULL,
    hierarchy_level INTEGER DEFAULT 0,

    -- Flags
    is_system BOOLEAN DEFAULT FALSE,      -- No editable por usuarios
    is_default BOOLEAN DEFAULT FALSE,     -- Asignado a nuevos usuarios
    is_superadmin BOOLEAN DEFAULT FALSE,  -- Acceso total

    -- Metadata
    metadata JSONB DEFAULT '{}',

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_by UUID REFERENCES auth.users(id),
    deleted_at TIMESTAMPTZ,

    -- Constraint: nombre unico por tenant (o global si tenant_id es NULL)
    UNIQUE NULLS NOT DISTINCT (tenant_id, name)
);

-- Indices para roles
CREATE INDEX IF NOT EXISTS idx_roles_tenant ON users.roles(tenant_id);
CREATE INDEX IF NOT EXISTS idx_roles_parent ON users.roles(parent_role_id);
CREATE INDEX IF NOT EXISTS idx_roles_system ON users.roles(is_system) WHERE is_system = TRUE;
CREATE INDEX IF NOT EXISTS idx_roles_default ON users.roles(tenant_id, is_default) WHERE is_default = TRUE;

-- =====================
-- TABLA: users.permissions
-- Permisos granulares del sistema (US-004)
-- =====================
CREATE TABLE IF NOT EXISTS users.permissions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Identificacion
    resource VARCHAR(100) NOT NULL,       -- users, tenants, branches, invoices, etc.
    action VARCHAR(50) NOT NULL,          -- create, read, update, delete, export, etc.
    scope VARCHAR(50) DEFAULT 'own',      -- own, tenant, global

    -- Info
    display_name VARCHAR(255),
    description TEXT,
    category VARCHAR(100),                -- auth, billing, inventory, sales, etc.

    -- Flags
    is_dangerous BOOLEAN DEFAULT FALSE,   -- Requiere confirmacion adicional

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(resource, action, scope)
);

-- Indices para permissions
CREATE INDEX IF NOT EXISTS idx_permissions_resource ON users.permissions(resource);
CREATE INDEX IF NOT EXISTS idx_permissions_category ON users.permissions(category);

-- =====================
-- TABLA: users.role_permissions
-- Asignacion de permisos a roles (US-004)
-- =====================
CREATE TABLE IF NOT EXISTS users.role_permissions (
    role_id UUID NOT NULL REFERENCES users.roles(id) ON DELETE CASCADE,
    permission_id UUID NOT NULL REFERENCES users.permissions(id) ON DELETE CASCADE,

    -- Condiciones opcionales
    conditions JSONB DEFAULT '{}',  -- Condiciones adicionales (ej: solo ciertos estados)

    -- Metadata
    granted_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    granted_by UUID REFERENCES auth.users(id),

    PRIMARY KEY (role_id, permission_id)
);

-- Indices para role_permissions
CREATE INDEX IF NOT EXISTS idx_role_permissions_role ON users.role_permissions(role_id);
CREATE INDEX IF NOT EXISTS idx_role_permissions_permission ON users.role_permissions(permission_id);

-- =====================
-- TABLA: users.user_roles
-- Asignacion de roles a usuarios (US-004)
-- =====================
CREATE TABLE IF NOT EXISTS users.user_roles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
    role_id UUID NOT NULL REFERENCES users.roles(id) ON DELETE CASCADE,

    -- Contexto
    tenant_id UUID REFERENCES auth.tenants(id) ON DELETE CASCADE,
    branch_id UUID REFERENCES core.branches(id) ON DELETE CASCADE,  -- Opcional: rol por sucursal

    -- Flags
    is_primary BOOLEAN DEFAULT FALSE,

    -- Vigencia
    valid_from TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    valid_until TIMESTAMPTZ,

    -- Metadata
    assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    assigned_by UUID REFERENCES auth.users(id),
    revoked_at TIMESTAMPTZ,
    revoked_by UUID REFERENCES auth.users(id),

    -- Constraint: un usuario solo puede tener un rol una vez por branch (o global si branch es NULL)
    UNIQUE (user_id, role_id, branch_id)
);

-- Indices para user_roles
CREATE INDEX IF NOT EXISTS idx_user_roles_user ON users.user_roles(user_id);
CREATE INDEX IF NOT EXISTS idx_user_roles_role ON users.user_roles(role_id);
CREATE INDEX IF NOT EXISTS idx_user_roles_tenant ON users.user_roles(tenant_id);
CREATE INDEX IF NOT EXISTS idx_user_roles_branch ON users.user_roles(branch_id) WHERE branch_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_user_roles_active ON users.user_roles(user_id, revoked_at) WHERE revoked_at IS NULL;

-- =====================
-- TABLA: users.invitations
-- Invitaciones de usuario (US-006)
-- =====================
CREATE TABLE IF NOT EXISTS users.invitations (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Destinatario
    email VARCHAR(255) NOT NULL,
    first_name VARCHAR(100),
    last_name VARCHAR(100),

    -- Token de invitacion
    token_hash VARCHAR(255) NOT NULL UNIQUE,
    token_expires_at TIMESTAMPTZ NOT NULL,

    -- Rol a asignar
    role_id UUID REFERENCES users.roles(id) ON DELETE SET NULL,
    branch_id UUID REFERENCES core.branches(id) ON DELETE SET NULL,

    -- Estado
    status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'expired', 'revoked')),

    -- Mensaje personalizado
    message TEXT,

    -- Metadata
    metadata JSONB DEFAULT '{}',

    -- Timestamps
    invited_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    invited_by UUID NOT NULL REFERENCES auth.users(id),
    accepted_at TIMESTAMPTZ,
    accepted_user_id UUID REFERENCES auth.users(id),
    resent_at TIMESTAMPTZ,
    resent_count INTEGER DEFAULT 0,

    -- Constraint: email unico por tenant mientras este pendiente
    CONSTRAINT unique_pending_invitation UNIQUE (tenant_id, email, status)
);

-- Indices para invitations
CREATE INDEX IF NOT EXISTS idx_invitations_tenant ON users.invitations(tenant_id);
CREATE INDEX IF NOT EXISTS idx_invitations_email ON users.invitations(email);
CREATE INDEX IF NOT EXISTS idx_invitations_token ON users.invitations(token_hash);
CREATE INDEX IF NOT EXISTS idx_invitations_status ON users.invitations(status) WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS idx_invitations_expires ON users.invitations(token_expires_at) WHERE status = 'pending';

-- =====================
-- TABLA: users.tenant_settings
-- Configuraciones por tenant (US-005)
-- =====================
CREATE TABLE IF NOT EXISTS users.tenant_settings (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE UNIQUE,

    -- Limites
    max_users INTEGER DEFAULT 10,
    max_branches INTEGER DEFAULT 5,
    max_storage_mb INTEGER DEFAULT 1024,

    -- Features habilitadas
    features_enabled TEXT[] DEFAULT '{}',

    -- Configuracion de branding
    branding JSONB DEFAULT '{
        "logo_url": null,
        "primary_color": "#2563eb",
        "secondary_color": "#64748b"
    }',

    -- Configuracion regional
    locale VARCHAR(10) DEFAULT 'es-MX',
    timezone VARCHAR(50) DEFAULT 'America/Mexico_City',
    currency VARCHAR(3) DEFAULT 'MXN',
    date_format VARCHAR(20) DEFAULT 'DD/MM/YYYY',

    -- Configuracion de seguridad
    security_settings JSONB DEFAULT '{
        "require_mfa": false,
        "session_timeout_minutes": 480,
        "password_min_length": 8,
        "password_require_special": true
    }',

    -- Configuracion de notificaciones
    notification_settings JSONB DEFAULT '{
        "email_enabled": true,
        "push_enabled": true,
        "sms_enabled": false
    }',

    -- Metadata
    metadata JSONB DEFAULT '{}',

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- =====================
-- TABLA: users.profile_role_mapping
-- Mapeo de perfiles ERP a roles RBAC (US-030)
-- =====================
CREATE TABLE IF NOT EXISTS users.profile_role_mapping (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    profile_code VARCHAR(10) NOT NULL,  -- ADM, CNT, VNT, ALM, etc.
    role_id UUID NOT NULL REFERENCES users.roles(id) ON DELETE CASCADE,

    -- Flags
    is_default BOOLEAN DEFAULT TRUE,

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(profile_code, role_id)
);

-- Indice para profile_role_mapping
CREATE INDEX IF NOT EXISTS idx_profile_role_mapping_profile ON users.profile_role_mapping(profile_code);

-- =====================
-- RLS POLICIES
-- =====================
ALTER TABLE users.roles ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_roles ON users.roles
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);

ALTER TABLE users.role_permissions ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_role_permissions ON users.role_permissions
    USING (role_id IN (
        SELECT id FROM users.roles
        WHERE tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL
    ));

ALTER TABLE users.user_roles ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_user_roles ON users.user_roles
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid OR tenant_id IS NULL);

ALTER TABLE users.invitations ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_invitations ON users.invitations
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

ALTER TABLE users.tenant_settings ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_settings ON users.tenant_settings
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- =====================
-- FUNCIONES
-- =====================

-- Funcion para verificar si un usuario tiene un permiso especifico
CREATE OR REPLACE FUNCTION users.has_permission(
    p_user_id UUID,
    p_resource VARCHAR(100),
    p_action VARCHAR(50),
    p_scope VARCHAR(50) DEFAULT 'own'
)
RETURNS BOOLEAN AS $$
DECLARE
    has_perm BOOLEAN;
BEGIN
    -- Verificar si es superadmin
    IF EXISTS (
        SELECT 1 FROM auth.users
        WHERE id = p_user_id AND is_superadmin = TRUE
    ) THEN
        RETURN TRUE;
    END IF;

    -- Verificar permisos via roles
    SELECT EXISTS (
        SELECT 1
        FROM users.user_roles ur
        JOIN users.role_permissions rp ON rp.role_id = ur.role_id
        JOIN users.permissions p ON p.id = rp.permission_id
        WHERE ur.user_id = p_user_id
        AND ur.revoked_at IS NULL
        AND (ur.valid_until IS NULL OR ur.valid_until > CURRENT_TIMESTAMP)
        AND p.resource = p_resource
        AND p.action = p_action
        AND (p.scope = p_scope OR p.scope = 'global')
    ) INTO has_perm;

    RETURN has_perm;
END;
$$ LANGUAGE plpgsql STABLE;

-- Funcion para obtener todos los permisos de un usuario
CREATE OR REPLACE FUNCTION users.get_user_permissions(p_user_id UUID)
RETURNS TABLE (
    resource VARCHAR(100),
    action VARCHAR(50),
    scope VARCHAR(50),
    conditions JSONB
) AS $$
BEGIN
    -- Si es superadmin, devolver wildcard
    IF EXISTS (
        SELECT 1 FROM auth.users
        WHERE id = p_user_id AND is_superadmin = TRUE
    ) THEN
        RETURN QUERY
        SELECT '*'::VARCHAR(100), '*'::VARCHAR(50), 'global'::VARCHAR(50), '{}'::JSONB;
        RETURN;
    END IF;

    RETURN QUERY
    SELECT DISTINCT
        p.resource,
        p.action,
        p.scope,
        rp.conditions
    FROM users.user_roles ur
    JOIN users.role_permissions rp ON rp.role_id = ur.role_id
    JOIN users.permissions p ON p.id = rp.permission_id
    WHERE ur.user_id = p_user_id
    AND ur.revoked_at IS NULL
    AND (ur.valid_until IS NULL OR ur.valid_until > CURRENT_TIMESTAMP);
END;
$$ LANGUAGE plpgsql STABLE;

-- Funcion para obtener permisos heredados de un rol
CREATE OR REPLACE FUNCTION users.get_role_permissions_with_inheritance(p_role_id UUID)
RETURNS TABLE (
    permission_id UUID,
    resource VARCHAR(100),
    action VARCHAR(50),
    scope VARCHAR(50),
    inherited_from UUID
) AS $$
WITH RECURSIVE role_hierarchy AS (
    -- Rol base
    SELECT id, parent_role_id, 0 as level
    FROM users.roles
    WHERE id = p_role_id

    UNION ALL

    -- Roles padre (herencia)
    SELECT r.id, r.parent_role_id, rh.level + 1
    FROM users.roles r
    JOIN role_hierarchy rh ON r.id = rh.parent_role_id
    WHERE rh.level < 10  -- Limite de profundidad
)
SELECT
    p.id as permission_id,
    p.resource,
    p.action,
    p.scope,
    rh.id as inherited_from
FROM role_hierarchy rh
JOIN users.role_permissions rp ON rp.role_id = rh.id
JOIN users.permissions p ON p.id = rp.permission_id;
$$ LANGUAGE sql STABLE;

-- Funcion para limpiar invitaciones expiradas
CREATE OR REPLACE FUNCTION users.cleanup_expired_invitations()
RETURNS INTEGER AS $$
DECLARE
    updated_count INTEGER;
BEGIN
    UPDATE users.invitations
    SET status = 'expired'
    WHERE status = 'pending'
    AND token_expires_at < CURRENT_TIMESTAMP;

    GET DIAGNOSTICS updated_count = ROW_COUNT;
    RETURN updated_count;
END;
$$ LANGUAGE plpgsql;

-- =====================
-- TRIGGERS
-- =====================

-- Trigger para actualizar updated_at en roles
CREATE OR REPLACE FUNCTION users.update_role_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_roles_updated_at
    BEFORE UPDATE ON users.roles
    FOR EACH ROW
    EXECUTE FUNCTION users.update_role_timestamp();

-- Trigger para actualizar updated_at en tenant_settings
CREATE TRIGGER trg_tenant_settings_updated_at
    BEFORE UPDATE ON users.tenant_settings
    FOR EACH ROW
    EXECUTE FUNCTION users.update_role_timestamp();

-- =====================
-- SEED DATA: Permisos Base
-- =====================
INSERT INTO users.permissions (resource, action, scope, display_name, description, category) VALUES
-- Auth
('users', 'create', 'tenant', 'Crear usuarios', 'Crear nuevos usuarios en el tenant', 'auth'),
('users', 'read', 'tenant', 'Ver usuarios', 'Ver lista de usuarios del tenant', 'auth'),
('users', 'read', 'own', 'Ver perfil propio', 'Ver su propio perfil', 'auth'),
('users', 'update', 'tenant', 'Editar usuarios', 'Editar cualquier usuario del tenant', 'auth'),
('users', 'update', 'own', 'Editar perfil propio', 'Editar su propio perfil', 'auth'),
('users', 'delete', 'tenant', 'Eliminar usuarios', 'Eliminar usuarios del tenant', 'auth'),
('roles', 'create', 'tenant', 'Crear roles', 'Crear nuevos roles', 'auth'),
('roles', 'read', 'tenant', 'Ver roles', 'Ver roles del tenant', 'auth'),
('roles', 'update', 'tenant', 'Editar roles', 'Editar roles existentes', 'auth'),
('roles', 'delete', 'tenant', 'Eliminar roles', 'Eliminar roles', 'auth'),
('invitations', 'create', 'tenant', 'Invitar usuarios', 'Enviar invitaciones', 'auth'),
('invitations', 'read', 'tenant', 'Ver invitaciones', 'Ver invitaciones pendientes', 'auth'),
('invitations', 'delete', 'tenant', 'Cancelar invitaciones', 'Revocar invitaciones', 'auth'),

-- Tenants
('tenants', 'read', 'own', 'Ver configuracion', 'Ver configuracion del tenant', 'tenants'),
('tenants', 'update', 'own', 'Editar configuracion', 'Editar configuracion del tenant', 'tenants'),
('tenant_settings', 'read', 'own', 'Ver ajustes', 'Ver ajustes del tenant', 'tenants'),
('tenant_settings', 'update', 'own', 'Editar ajustes', 'Editar ajustes del tenant', 'tenants'),

-- Branches
('branches', 'create', 'tenant', 'Crear sucursales', 'Crear nuevas sucursales', 'branches'),
('branches', 'read', 'tenant', 'Ver sucursales', 'Ver todas las sucursales', 'branches'),
('branches', 'read', 'own', 'Ver sucursal asignada', 'Ver solo su sucursal', 'branches'),
('branches', 'update', 'tenant', 'Editar sucursales', 'Editar cualquier sucursal', 'branches'),
('branches', 'delete', 'tenant', 'Eliminar sucursales', 'Eliminar sucursales', 'branches'),

-- Billing
('billing', 'read', 'tenant', 'Ver facturacion', 'Ver informacion de facturacion', 'billing'),
('billing', 'update', 'tenant', 'Gestionar facturacion', 'Cambiar plan, metodo de pago', 'billing'),
('invoices', 'read', 'tenant', 'Ver facturas', 'Ver historial de facturas', 'billing'),
('invoices', 'export', 'tenant', 'Exportar facturas', 'Descargar facturas', 'billing'),

-- Audit
('audit_logs', 'read', 'tenant', 'Ver auditoria', 'Ver logs de auditoria', 'audit'),
('audit_logs', 'export', 'tenant', 'Exportar auditoria', 'Exportar logs', 'audit'),
('activity', 'read', 'own', 'Ver mi actividad', 'Ver actividad propia', 'audit'),

-- Notifications
('notifications', 'read', 'own', 'Ver notificaciones', 'Ver notificaciones propias', 'notifications'),
('notifications', 'update', 'own', 'Gestionar notificaciones', 'Marcar como leidas', 'notifications'),
('notification_settings', 'read', 'own', 'Ver preferencias', 'Ver preferencias de notificacion', 'notifications'),
('notification_settings', 'update', 'own', 'Editar preferencias', 'Editar preferencias', 'notifications')
ON CONFLICT DO NOTHING;

-- =====================
-- SEED DATA: Roles Base del Sistema
-- =====================
INSERT INTO users.roles (id, tenant_id, name, display_name, description, is_system, is_superadmin, hierarchy_level, icon, color) VALUES
('10000000-0000-0000-0000-000000000001', NULL, 'superadmin', 'Super Administrador', 'Acceso total a la plataforma', TRUE, TRUE, 0, 'shield-check', '#dc2626'),
('10000000-0000-0000-0000-000000000002', NULL, 'admin', 'Administrador', 'Administrador del tenant', TRUE, FALSE, 1, 'shield', '#ea580c'),
('10000000-0000-0000-0000-000000000003', NULL, 'manager', 'Gerente', 'Gerente con acceso a reportes', TRUE, FALSE, 2, 'briefcase', '#0891b2'),
('10000000-0000-0000-0000-000000000004', NULL, 'user', 'Usuario', 'Usuario estandar', TRUE, FALSE, 3, 'user', '#64748b'),
('10000000-0000-0000-0000-000000000005', NULL, 'viewer', 'Visor', 'Solo lectura', TRUE, FALSE, 4, 'eye', '#94a3b8')
ON CONFLICT DO NOTHING;

-- Asignar permisos al rol Admin
INSERT INTO users.role_permissions (role_id, permission_id)
SELECT '10000000-0000-0000-0000-000000000002', id
FROM users.permissions
WHERE resource NOT IN ('audit_logs')  -- Admin no tiene acceso a audit
ON CONFLICT DO NOTHING;

-- Asignar permisos al rol Manager
INSERT INTO users.role_permissions (role_id, permission_id)
SELECT '10000000-0000-0000-0000-000000000003', id
FROM users.permissions
WHERE scope = 'own'
OR (resource IN ('branches', 'users', 'invoices') AND action = 'read')
ON CONFLICT DO NOTHING;

-- Asignar permisos al rol User
INSERT INTO users.role_permissions (role_id, permission_id)
SELECT '10000000-0000-0000-0000-000000000004', id
FROM users.permissions
WHERE scope = 'own'
ON CONFLICT DO NOTHING;

-- Asignar permisos al rol Viewer
INSERT INTO users.role_permissions (role_id, permission_id)
SELECT '10000000-0000-0000-0000-000000000005', id
FROM users.permissions
WHERE action = 'read' AND scope = 'own'
ON CONFLICT DO NOTHING;

-- =====================
-- SEED DATA: Mapeo de Perfiles ERP a Roles (US-030)
-- =====================
INSERT INTO users.profile_role_mapping (profile_code, role_id) VALUES
('ADM', '10000000-0000-0000-0000-000000000002'),  -- Admin
('CNT', '10000000-0000-0000-0000-000000000003'),  -- Manager
('VNT', '10000000-0000-0000-0000-000000000004'),  -- User
('CMP', '10000000-0000-0000-0000-000000000004'),  -- User
('ALM', '10000000-0000-0000-0000-000000000004'),  -- User
('HRH', '10000000-0000-0000-0000-000000000003'),  -- Manager
('PRD', '10000000-0000-0000-0000-000000000004'),  -- User
('EMP', '10000000-0000-0000-0000-000000000005'),  -- Viewer
('GER', '10000000-0000-0000-0000-000000000003'),  -- Manager
('AUD', '10000000-0000-0000-0000-000000000005')   -- Viewer (read-only)
ON CONFLICT DO NOTHING;

-- =====================
-- COMENTARIOS
-- =====================
COMMENT ON TABLE users.roles IS 'Roles del sistema con soporte para herencia';
COMMENT ON TABLE users.permissions IS 'Permisos granulares (resource.action.scope)';
COMMENT ON TABLE users.role_permissions IS 'Asignacion de permisos a roles';
COMMENT ON TABLE users.user_roles IS 'Asignacion de roles a usuarios';
COMMENT ON TABLE users.invitations IS 'Invitaciones para nuevos usuarios';
COMMENT ON TABLE users.tenant_settings IS 'Configuraciones personalizadas por tenant';
COMMENT ON TABLE users.profile_role_mapping IS 'Mapeo de perfiles ERP a roles RBAC';

COMMENT ON FUNCTION users.has_permission IS 'Verifica si un usuario tiene un permiso especifico';
COMMENT ON FUNCTION users.get_user_permissions IS 'Obtiene todos los permisos de un usuario';
COMMENT ON FUNCTION users.get_role_permissions_with_inheritance IS 'Obtiene permisos de un rol incluyendo herencia';
