-- =====================================================
-- SCHEMA: auth
-- PROPÓSITO: Autenticación, usuarios, roles, permisos
-- MÓDULOS: MGN-001 (Fundamentos), MGN-002 (Empresas)
-- FECHA: 2025-11-24
-- =====================================================

-- Crear schema
CREATE SCHEMA IF NOT EXISTS auth;

-- =====================================================
-- TYPES (ENUMs)
-- =====================================================

CREATE TYPE auth.user_status AS ENUM (
  'active',
  'inactive',
  'suspended',
  'pending_verification'
);

CREATE TYPE auth.tenant_status AS ENUM (
  'active',
  'suspended',
  'trial',
  'cancelled'
);

CREATE TYPE auth.tenant_plan AS ENUM (
  'basic',
  'standard',
  'premium',
  'enterprise'
);

CREATE TYPE auth.session_status AS ENUM (
  'active',
  'expired',
  'revoked'
);

CREATE TYPE auth.permission_action AS ENUM (
  'create',
  'read',
  'update',
  'delete',
  'approve',
  'cancel',
  'export'
);

-- =====================================================
-- TABLES
-- =====================================================

-- Tabla: tenants (Multi-Tenancy)
CREATE TABLE auth.tenants (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name VARCHAR(255) NOT NULL,
  subdomain VARCHAR(100) UNIQUE NOT NULL,
  schema_name VARCHAR(100) UNIQUE NOT NULL,
  status auth.tenant_status NOT NULL DEFAULT 'active',
  plan auth.tenant_plan NOT NULL DEFAULT 'basic',

  -- Límites y uso
  max_users INTEGER DEFAULT 10,
  max_storage_mb INTEGER DEFAULT 1024,
  current_storage_mb INTEGER DEFAULT 0,

  -- Información de contacto
  custom_domain VARCHAR(255),
  contact_email VARCHAR(255),
  contact_phone VARCHAR(50),
  billing_email VARCHAR(255),
  tax_id VARCHAR(50),

  -- Suscripción
  trial_ends_at TIMESTAMP,
  subscription_ends_at TIMESTAMP,

  -- Configuración
  settings JSONB DEFAULT '{}',
  metadata JSONB DEFAULT '{}',

  -- Auditoría (tenant no tiene tenant_id)
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID, -- Puede ser NULL para primer tenant
  updated_at TIMESTAMP,
  updated_by UUID,
  deleted_at TIMESTAMP,
  deleted_by UUID,

  CONSTRAINT chk_tenants_subdomain_format CHECK (subdomain ~ '^[a-z0-9-]+$'),
  CONSTRAINT chk_tenants_max_users CHECK (max_users > 0),
  CONSTRAINT chk_tenants_max_storage CHECK (max_storage_mb > 0),
  CONSTRAINT chk_tenants_current_storage CHECK (current_storage_mb >= 0)
);

-- Tabla: companies (Multi-Company dentro de tenant)
CREATE TABLE auth.companies (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
  name VARCHAR(255) NOT NULL,
  legal_name VARCHAR(255),
  tax_id VARCHAR(50),
  currency_id UUID, -- FK a core.currencies (se crea después)
  parent_company_id UUID REFERENCES auth.companies(id),
  partner_id UUID, -- FK a core.partners (se crea después)
  settings JSONB DEFAULT '{}',

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID,
  updated_at TIMESTAMP,
  updated_by UUID,
  deleted_at TIMESTAMP,
  deleted_by UUID,

  CONSTRAINT uq_companies_tax_id_tenant UNIQUE (tenant_id, tax_id),
  CONSTRAINT chk_companies_no_self_parent CHECK (id != parent_company_id)
);

-- Tabla: users
CREATE TABLE auth.users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
  email VARCHAR(255) NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  full_name VARCHAR(255) NOT NULL,
  avatar_url VARCHAR(500),
  status auth.user_status NOT NULL DEFAULT 'active',
  is_superuser BOOLEAN NOT NULL DEFAULT FALSE,
  email_verified_at TIMESTAMP,
  last_login_at TIMESTAMP,
  last_login_ip INET,
  login_count INTEGER DEFAULT 0,
  language VARCHAR(10) DEFAULT 'es', -- es, en
  timezone VARCHAR(50) DEFAULT 'America/Mexico_City',
  settings JSONB DEFAULT '{}',

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID,
  updated_at TIMESTAMP,
  updated_by UUID,
  deleted_at TIMESTAMP,
  deleted_by UUID,

  CONSTRAINT uq_users_email_tenant UNIQUE (tenant_id, email),
  CONSTRAINT chk_users_email_format CHECK (email ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$')
);

-- Tabla: roles
CREATE TABLE auth.roles (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
  name VARCHAR(100) NOT NULL,
  code VARCHAR(50) NOT NULL,
  description TEXT,
  is_system BOOLEAN NOT NULL DEFAULT FALSE, -- Roles del sistema no editables
  color VARCHAR(20),

  -- Auditoría
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES auth.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES auth.users(id),
  deleted_at TIMESTAMP,
  deleted_by UUID REFERENCES auth.users(id),

  CONSTRAINT uq_roles_code_tenant UNIQUE (tenant_id, code)
);

-- Tabla: permissions
CREATE TABLE auth.permissions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  resource VARCHAR(100) NOT NULL, -- Tabla/endpoint
  action auth.permission_action NOT NULL,
  description TEXT,
  module VARCHAR(50), -- MGN-001, MGN-004, etc.

  -- Sin tenant_id: permisos son globales
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  CONSTRAINT uq_permissions_resource_action UNIQUE (resource, action)
);

-- Tabla: user_roles (many-to-many)
CREATE TABLE auth.user_roles (
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  role_id UUID NOT NULL REFERENCES auth.roles(id) ON DELETE CASCADE,
  assigned_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  assigned_by UUID REFERENCES auth.users(id),

  PRIMARY KEY (user_id, role_id)
);

-- Tabla: role_permissions (many-to-many)
CREATE TABLE auth.role_permissions (
  role_id UUID NOT NULL REFERENCES auth.roles(id) ON DELETE CASCADE,
  permission_id UUID NOT NULL REFERENCES auth.permissions(id) ON DELETE CASCADE,
  granted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  granted_by UUID REFERENCES auth.users(id),

  PRIMARY KEY (role_id, permission_id)
);

-- Tabla: sessions
CREATE TABLE auth.sessions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  token VARCHAR(500) NOT NULL UNIQUE,
  refresh_token VARCHAR(500) UNIQUE,
  status auth.session_status NOT NULL DEFAULT 'active',
  expires_at TIMESTAMP NOT NULL,
  refresh_expires_at TIMESTAMP,
  ip_address INET,
  user_agent TEXT,
  device_info JSONB,

  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  revoked_at TIMESTAMP,
  revoked_reason VARCHAR(100),

  CONSTRAINT chk_sessions_expiration CHECK (expires_at > created_at),
  CONSTRAINT chk_sessions_refresh_expiration CHECK (
    refresh_expires_at IS NULL OR refresh_expires_at > expires_at
  )
);

-- Tabla: user_companies (many-to-many)
-- Usuario puede acceder a múltiples empresas
CREATE TABLE auth.user_companies (
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
  is_default BOOLEAN DEFAULT FALSE,
  assigned_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (user_id, company_id)
);

-- Tabla: password_resets
CREATE TABLE auth.password_resets (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  token VARCHAR(500) NOT NULL UNIQUE,
  expires_at TIMESTAMP NOT NULL,
  used_at TIMESTAMP,
  ip_address INET,

  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  CONSTRAINT chk_password_resets_expiration CHECK (expires_at > created_at)
);

-- =====================================================
-- INDICES
-- =====================================================

-- Tenants
CREATE INDEX idx_tenants_subdomain ON auth.tenants(subdomain);
CREATE INDEX idx_tenants_status ON auth.tenants(status) WHERE deleted_at IS NULL;
CREATE INDEX idx_tenants_created_at ON auth.tenants(created_at);
CREATE INDEX idx_tenants_plan ON auth.tenants(plan);
CREATE INDEX idx_tenants_custom_domain ON auth.tenants(custom_domain) WHERE custom_domain IS NOT NULL;
CREATE INDEX idx_tenants_trial_ends_at ON auth.tenants(trial_ends_at) WHERE trial_ends_at IS NOT NULL;

-- Companies
CREATE INDEX idx_companies_tenant_id ON auth.companies(tenant_id);
CREATE INDEX idx_companies_parent_company_id ON auth.companies(parent_company_id);
CREATE INDEX idx_companies_active ON auth.companies(tenant_id) WHERE deleted_at IS NULL;
CREATE INDEX idx_companies_tax_id ON auth.companies(tax_id);

-- Users
CREATE INDEX idx_users_tenant_id ON auth.users(tenant_id);
CREATE INDEX idx_users_email ON auth.users(email);
CREATE INDEX idx_users_status ON auth.users(status) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_email_tenant ON auth.users(tenant_id, email);
CREATE INDEX idx_users_created_at ON auth.users(created_at);

-- Roles
CREATE INDEX idx_roles_tenant_id ON auth.roles(tenant_id);
CREATE INDEX idx_roles_code ON auth.roles(code);
CREATE INDEX idx_roles_is_system ON auth.roles(is_system);

-- Permissions
CREATE INDEX idx_permissions_resource ON auth.permissions(resource);
CREATE INDEX idx_permissions_action ON auth.permissions(action);
CREATE INDEX idx_permissions_module ON auth.permissions(module);

-- Sessions
CREATE INDEX idx_sessions_user_id ON auth.sessions(user_id);
CREATE INDEX idx_sessions_token ON auth.sessions(token);
CREATE INDEX idx_sessions_status ON auth.sessions(status);
CREATE INDEX idx_sessions_expires_at ON auth.sessions(expires_at);

-- User Roles
CREATE INDEX idx_user_roles_user_id ON auth.user_roles(user_id);
CREATE INDEX idx_user_roles_role_id ON auth.user_roles(role_id);

-- Role Permissions
CREATE INDEX idx_role_permissions_role_id ON auth.role_permissions(role_id);
CREATE INDEX idx_role_permissions_permission_id ON auth.role_permissions(permission_id);

-- User Companies
CREATE INDEX idx_user_companies_user_id ON auth.user_companies(user_id);
CREATE INDEX idx_user_companies_company_id ON auth.user_companies(company_id);

-- Password Resets
CREATE INDEX idx_password_resets_user_id ON auth.password_resets(user_id);
CREATE INDEX idx_password_resets_token ON auth.password_resets(token);
CREATE INDEX idx_password_resets_expires_at ON auth.password_resets(expires_at);

-- =====================================================
-- FUNCTIONS
-- =====================================================

-- Función: get_current_tenant_id
CREATE OR REPLACE FUNCTION get_current_tenant_id()
RETURNS UUID AS $$
BEGIN
  RETURN current_setting('app.current_tenant_id', true)::UUID;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

COMMENT ON FUNCTION get_current_tenant_id() IS 'Obtiene el tenant_id del contexto actual';

-- Función: get_current_user_id
CREATE OR REPLACE FUNCTION get_current_user_id()
RETURNS UUID AS $$
BEGIN
  RETURN current_setting('app.current_user_id', true)::UUID;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

COMMENT ON FUNCTION get_current_user_id() IS 'Obtiene el user_id del contexto actual';

-- Función: get_current_company_id
CREATE OR REPLACE FUNCTION get_current_company_id()
RETURNS UUID AS $$
BEGIN
  RETURN current_setting('app.current_company_id', true)::UUID;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

COMMENT ON FUNCTION get_current_company_id() IS 'Obtiene el company_id del contexto actual';

-- Función: user_has_permission
CREATE OR REPLACE FUNCTION auth.user_has_permission(
  p_user_id UUID,
  p_resource VARCHAR,
  p_action auth.permission_action
)
RETURNS BOOLEAN AS $$
DECLARE
  v_has_permission BOOLEAN;
BEGIN
  -- Superusers tienen todos los permisos
  IF EXISTS (
    SELECT 1 FROM auth.users
    WHERE id = p_user_id AND is_superuser = TRUE AND deleted_at IS NULL
  ) THEN
    RETURN TRUE;
  END IF;

  -- Verificar si el usuario tiene el permiso a través de sus roles
  SELECT EXISTS (
    SELECT 1
    FROM auth.user_roles ur
    JOIN auth.role_permissions rp ON ur.role_id = rp.role_id
    JOIN auth.permissions p ON rp.permission_id = p.id
    WHERE ur.user_id = p_user_id
      AND p.resource = p_resource
      AND p.action = p_action
  ) INTO v_has_permission;

  RETURN v_has_permission;
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

COMMENT ON FUNCTION auth.user_has_permission IS 'Verifica si un usuario tiene un permiso específico';

-- Función: clean_expired_sessions
CREATE OR REPLACE FUNCTION auth.clean_expired_sessions()
RETURNS INTEGER AS $$
DECLARE
  v_deleted_count INTEGER;
BEGIN
  WITH deleted AS (
    DELETE FROM auth.sessions
    WHERE status = 'active'
      AND expires_at < CURRENT_TIMESTAMP
    RETURNING id
  )
  SELECT COUNT(*) INTO v_deleted_count FROM deleted;

  RETURN v_deleted_count;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION auth.clean_expired_sessions IS 'Limpia sesiones expiradas (ejecutar periódicamente)';

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

-- Trigger: Actualizar updated_at automáticamente
CREATE OR REPLACE FUNCTION auth.update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = CURRENT_TIMESTAMP;
  NEW.updated_by = get_current_user_id();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_tenants_updated_at
  BEFORE UPDATE ON auth.tenants
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

CREATE TRIGGER trg_companies_updated_at
  BEFORE UPDATE ON auth.companies
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

CREATE TRIGGER trg_users_updated_at
  BEFORE UPDATE ON auth.users
  FOR EACH ROW
  EXECUTE FUNCTION auth.update_updated_at_column();

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

-- Trigger: Validar que tenant tenga al menos 1 admin
CREATE OR REPLACE FUNCTION auth.validate_tenant_has_admin()
RETURNS TRIGGER AS $$
BEGIN
  -- Al eliminar user_role, verificar que no sea el último admin
  IF TG_OP = 'DELETE' THEN
    IF EXISTS (
      SELECT 1
      FROM auth.users u
      JOIN auth.roles r ON r.tenant_id = u.tenant_id
      WHERE u.id = OLD.user_id
        AND r.code = 'admin'
        AND r.id = OLD.role_id
    ) THEN
      -- Contar admins restantes
      IF NOT EXISTS (
        SELECT 1
        FROM auth.user_roles ur
        JOIN auth.roles r ON r.id = ur.role_id
        JOIN auth.users u ON u.id = ur.user_id
        WHERE r.code = 'admin'
          AND u.tenant_id = (SELECT tenant_id FROM auth.users WHERE id = OLD.user_id)
          AND ur.user_id != OLD.user_id
      ) THEN
        RAISE EXCEPTION 'Cannot remove last admin from tenant';
      END IF;
    END IF;
  END IF;

  RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_validate_tenant_has_admin
  BEFORE DELETE ON auth.user_roles
  FOR EACH ROW
  EXECUTE FUNCTION auth.validate_tenant_has_admin();

-- Trigger: Auto-marcar sesión como expirada
CREATE OR REPLACE FUNCTION auth.auto_expire_session()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.expires_at < CURRENT_TIMESTAMP AND NEW.status = 'active' THEN
    NEW.status = 'expired';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_auto_expire_session
  BEFORE UPDATE ON auth.sessions
  FOR EACH ROW
  EXECUTE FUNCTION auth.auto_expire_session();

-- =====================================================
-- ROW LEVEL SECURITY (RLS)
-- =====================================================

-- Habilitar RLS en tablas con tenant_id
ALTER TABLE auth.companies ENABLE ROW LEVEL SECURITY;
ALTER TABLE auth.users ENABLE ROW LEVEL SECURITY;
ALTER TABLE auth.roles ENABLE ROW LEVEL SECURITY;

-- Policy: Tenant Isolation - Companies
CREATE POLICY tenant_isolation_companies
ON auth.companies
USING (tenant_id = get_current_tenant_id());

-- Policy: Tenant Isolation - Users
CREATE POLICY tenant_isolation_users
ON auth.users
USING (tenant_id = get_current_tenant_id());

-- Policy: Tenant Isolation - Roles
CREATE POLICY tenant_isolation_roles
ON auth.roles
USING (tenant_id = get_current_tenant_id());

-- =====================================================
-- DATOS INICIALES (Seed Data)
-- =====================================================

-- Permisos estándar para recursos comunes
INSERT INTO auth.permissions (resource, action, description, module) VALUES
-- Auth
('users', 'create', 'Crear usuarios', 'MGN-001'),
('users', 'read', 'Ver usuarios', 'MGN-001'),
('users', 'update', 'Actualizar usuarios', 'MGN-001'),
('users', 'delete', 'Eliminar usuarios', 'MGN-001'),
('roles', 'create', 'Crear roles', 'MGN-001'),
('roles', 'read', 'Ver roles', 'MGN-001'),
('roles', 'update', 'Actualizar roles', 'MGN-001'),
('roles', 'delete', 'Eliminar roles', 'MGN-001'),

-- Financial
('invoices', 'create', 'Crear facturas', 'MGN-004'),
('invoices', 'read', 'Ver facturas', 'MGN-004'),
('invoices', 'update', 'Actualizar facturas', 'MGN-004'),
('invoices', 'delete', 'Eliminar facturas', 'MGN-004'),
('invoices', 'approve', 'Aprobar facturas', 'MGN-004'),
('invoices', 'cancel', 'Cancelar facturas', 'MGN-004'),
('journal_entries', 'create', 'Crear asientos contables', 'MGN-004'),
('journal_entries', 'read', 'Ver asientos contables', 'MGN-004'),
('journal_entries', 'approve', 'Aprobar asientos contables', 'MGN-004'),

-- Purchase
('purchase_orders', 'create', 'Crear órdenes de compra', 'MGN-006'),
('purchase_orders', 'read', 'Ver órdenes de compra', 'MGN-006'),
('purchase_orders', 'update', 'Actualizar órdenes de compra', 'MGN-006'),
('purchase_orders', 'delete', 'Eliminar órdenes de compra', 'MGN-006'),
('purchase_orders', 'approve', 'Aprobar órdenes de compra', 'MGN-006'),

-- Sales
('sale_orders', 'create', 'Crear órdenes de venta', 'MGN-007'),
('sale_orders', 'read', 'Ver órdenes de venta', 'MGN-007'),
('sale_orders', 'update', 'Actualizar órdenes de venta', 'MGN-007'),
('sale_orders', 'delete', 'Eliminar órdenes de venta', 'MGN-007'),
('sale_orders', 'approve', 'Aprobar órdenes de venta', 'MGN-007'),

-- Inventory
('products', 'create', 'Crear productos', 'MGN-005'),
('products', 'read', 'Ver productos', 'MGN-005'),
('products', 'update', 'Actualizar productos', 'MGN-005'),
('products', 'delete', 'Eliminar productos', 'MGN-005'),
('stock_moves', 'create', 'Crear movimientos de inventario', 'MGN-005'),
('stock_moves', 'read', 'Ver movimientos de inventario', 'MGN-005'),
('stock_moves', 'approve', 'Aprobar movimientos de inventario', 'MGN-005'),

-- Projects
('projects', 'create', 'Crear proyectos', 'MGN-011'),
('projects', 'read', 'Ver proyectos', 'MGN-011'),
('projects', 'update', 'Actualizar proyectos', 'MGN-011'),
('projects', 'delete', 'Eliminar proyectos', 'MGN-011'),
('tasks', 'create', 'Crear tareas', 'MGN-011'),
('tasks', 'read', 'Ver tareas', 'MGN-011'),
('tasks', 'update', 'Actualizar tareas', 'MGN-011'),
('tasks', 'delete', 'Eliminar tareas', 'MGN-011'),

-- Reports
('reports', 'read', 'Ver reportes', 'MGN-012'),
('reports', 'export', 'Exportar reportes', 'MGN-012');

-- =====================================================
-- COMENTARIOS EN TABLAS
-- =====================================================

COMMENT ON SCHEMA auth IS 'Schema de autenticación, usuarios, roles y permisos';
COMMENT ON TABLE auth.tenants IS 'Tenants (organizaciones raíz) con schema-level isolation. Incluye planes de suscripción, límites de almacenamiento y datos de contacto/facturación.';
COMMENT ON TABLE auth.companies IS 'Empresas dentro de un tenant (multi-company)';
COMMENT ON TABLE auth.users IS 'Usuarios del sistema con RBAC';
COMMENT ON TABLE auth.roles IS 'Roles con permisos asignados';
COMMENT ON TABLE auth.permissions IS 'Permisos granulares por recurso y acción';
COMMENT ON TABLE auth.user_roles IS 'Asignación de roles a usuarios (many-to-many)';
COMMENT ON TABLE auth.role_permissions IS 'Asignación de permisos a roles (many-to-many)';
COMMENT ON TABLE auth.sessions IS 'Sesiones JWT activas de usuarios';
COMMENT ON TABLE auth.user_companies IS 'Asignación de usuarios a empresas (multi-company)';
COMMENT ON TABLE auth.password_resets IS 'Tokens de reset de contraseña';

-- =====================================================
-- VISTAS ÚTILES
-- =====================================================

-- Vista: user_permissions (permisos efectivos de usuario)
CREATE OR REPLACE VIEW auth.user_permissions_view AS
SELECT DISTINCT
  ur.user_id,
  u.email,
  u.full_name,
  p.resource,
  p.action,
  p.description,
  r.name as role_name,
  r.code as role_code
FROM auth.user_roles ur
JOIN auth.users u ON ur.user_id = u.id
JOIN auth.roles r ON ur.role_id = r.id
JOIN auth.role_permissions rp ON r.id = rp.role_id
JOIN auth.permissions p ON rp.permission_id = p.id
WHERE u.deleted_at IS NULL
  AND u.status = 'active';

COMMENT ON VIEW auth.user_permissions_view IS 'Vista de permisos efectivos por usuario';

-- Vista: active_sessions (sesiones activas)
CREATE OR REPLACE VIEW auth.active_sessions_view AS
SELECT
  s.id,
  s.user_id,
  u.email,
  u.full_name,
  s.ip_address,
  s.user_agent,
  s.created_at as login_at,
  s.expires_at,
  EXTRACT(EPOCH FROM (s.expires_at - CURRENT_TIMESTAMP))/60 as minutes_until_expiry
FROM auth.sessions s
JOIN auth.users u ON s.user_id = u.id
WHERE s.status = 'active'
  AND s.expires_at > CURRENT_TIMESTAMP;

COMMENT ON VIEW auth.active_sessions_view IS 'Vista de sesiones activas con tiempo restante';

-- =====================================================
-- FIN DEL SCHEMA AUTH
-- =====================================================
