/**
 * 🔐 PERMISSION MIDDLEWARE - Middleware de Validação de Permissões
 * 
 * Middleware para Hono que valida permissões antes de executar handlers.
 * 
 * RESPONSABILIDADES:
 * - Validar token de autenticação
 * - Carregar usuário do banco
 * - Verificar se usuário tem permissão necessária
 * - Retornar 403 se não tiver permissão
 * - Logs estruturados de acesso
 * 
 * USO:
 * ```tsx
 * app.post('/facturas',
 *   requirePermission('faturacao.factura.criar'),
 *   async (c) => {
 *     // Handler só executa se tiver permissão
 *   }
 * );
 * ```
 * 
 * @module permission-middleware
 */

import { Context, Next } from 'hono';
import { createClient } from '../../src/compat/supabase.js';
import type { Usuario } from './authorization';
import * as kv from './kv_store.tsx'; // ✅ FASE 5 FIX: Adicionar extensão .tsx

const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;

// ========== TIPOS ==========

export type PermissionKey = string;

interface PermissionCheckResult {
  allowed: boolean;
  motivo: string;
  usuario?: Usuario;
}

// ========== CARREGAR USUÁRIO ==========

/**
 * Carrega usuário do banco de dados a partir do token de autenticação
 * 
 * ✅ FASE 5 FIX: Agora usa getByPrefix do KV Store e filtra manualmente
 * ✅ AUTO-PROVISIONING: Cria automaticamente usuário no KV se não existir
 */
async function loadUserFromToken(authToken: string): Promise<Usuario | null> {
  const supabase = createClient(supabaseUrl, supabaseServiceKey);

  try {
    // ✅ ETAPA 1: Validar token com Supabase Auth
    const { data: { user: authUser }, error: authError } = await supabase.auth.getUser(authToken);

    if (authError || !authUser) {
      console.error('❌ [loadUserFromToken] Token inválido:', authError);
      return null;
    }

    console.log('✅ [loadUserFromToken] Token válido para:', authUser.email);

    // ✅ FASE 5 FIX: Buscar usuário usando getByPrefix e filtrar manualmente
    const usuarios = await kv.getByPrefix<Usuario>('usuario:');
    
    // ✅ CORREÇÃO: Filtrar usuários válidos antes de procurar
    const usuariosValidos = usuarios.filter(u => 
      u != null && 
      u.email && 
      typeof u.email === 'string' && 
      u.email.trim().length > 0
    );
    
    if (!usuariosValidos || usuariosValidos.length === 0) {
      console.error('❌ [loadUserFromToken] Nenhum usuário válido encontrado no KV Store');
      console.error('❌ [loadUserFromToken] authUserId procurado:', authUser.id);
      
      // ✅ AUTO-PROVISIONING: Criar usuário automaticamente
      console.log('🔄 [loadUserFromToken] Tentando auto-provisioning do usuário...');
      return await autoProvisionUser(authUser);
    }

    // Filtrar manualmente pelo authUserId
    let usuario = usuariosValidos.find(u => u.authUserId === authUser.id);

    // ✅ FIX CRÍTICO DE DADOS: Se o usuário logou e caiu no auto-provisioning anterior falho,
    // ele pode ter um registro com empresa errada (a primeira empresa da lista).
    // Vamos procurar se ele tem um registro legado com a empresa correta!
    const registrosDesseEmail = usuariosValidos.filter(u => u.email && authUser.email && u.email.toLowerCase() === authUser.email.toLowerCase());
    
    // Se temos mais de um registro para este email (ex: um do auto-provision e um legado com empresa)
    if (registrosDesseEmail.length > 1) {
      // O registro legado provavelmente tem um empresaId que NÃO é o da primeira empresa do sistema,
      // ou foi criado antes.
      const registroLegado = registrosDesseEmail.find(u => u.authUserId !== authUser.id && u.empresaId);
      
      if (usuario && registroLegado && registroLegado.empresaId && usuario.empresaId !== registroLegado.empresaId) {
        console.log(`🚨 [CRITICAL FIX] Restaurando dados da empresa para: ${authUser.email}`);
        console.log(`Mudando empresa de ${usuario.empresaId} para ${registroLegado.empresaId}`);
        usuario.empresaId = registroLegado.empresaId;
        usuario.permissoes = registroLegado.permissoes || usuario.permissoes;
        usuario.permissoesModulos = registroLegado.permissoesModulos || usuario.permissoesModulos;
        usuario.nivel = registroLegado.nivel || usuario.nivel;
        
        await kv.set(`usuario:${usuario.id}`, usuario);
      }
    }

    // ✅ FIX: Tentar encontrar por email caso seja um usuário legado sem authUserId e ainda não encontrado
    if (!usuario) {
      usuario = registrosDesseEmail.find(u => !u.authUserId || u.authUserId === undefined);
      
      if (usuario) {
        console.log(`🔄 [loadUserFromToken] Usuário legado encontrado por email (${authUser.email}). Atualizando authUserId...`);
        // Atualiza o usuário com o novo authUserId
        usuario.authUserId = authUser.id;
        
        // Salvar a alteração no KV Store
        await kv.set(`usuario:${usuario.id}`, usuario);
        await kv.set(`usuario:email:${usuario.email}`, usuario.id);
        
        console.log('✅ [loadUserFromToken] Usuário atualizado com novo authUserId:', authUser.id);
      }
    }

    if (!usuario) {
      console.error('❌ [loadUserFromToken] Usuário não encontrado no KV Store');
      console.error('❌ [loadUserFromToken] authUserId procurado:', authUser.id);
      console.error('❌ [loadUserFromToken] Total de usuários válidos no KV:', usuariosValidos.length);
      console.error('❌ [loadUserFromToken] Usuários válidos disponíveis:', usuariosValidos.map(u => ({ 
        email: u.email, 
        authUserId: u.authUserId 
      })));
      
      // ✅ AUTO-PROVISIONING: Criar usuário automaticamente
      console.log('🔄 [loadUserFromToken] Tentando auto-provisioning do usuário...');
      return await autoProvisionUser(authUser);
    }

    console.log('✅ [loadUserFromToken] Usuário carregado:', { 
      email: usuario.email, 
      nivel: usuario.nivel,
      ativo: usuario.ativo 
    });

    return usuario;

  } catch (error) {
    console.error('❌ [loadUserFromToken] Erro:', error);
    return null;
  }
}

/**
 * Auto-provisioning: Cria automaticamente um usuário no KV Store
 * quando ele existe no Supabase Auth mas não no KV Store
 * 
 * ✅ COMPORTAMENTO:
 * - Procura por empresa associada ao email do usuário
 * - Se encontrar empresa, cria usuário com permissões básicas
 * - Se não encontrar, cria usuário inativo (admin deve ativar)
 */
async function autoProvisionUser(authUser: any): Promise<Usuario | null> {
  try {
    console.log('🔄 [autoProvisionUser] Iniciando auto-provisioning para:', authUser.email);
    console.log('🔄 [autoProvisionUser] authUserId:', authUser.id);
    
    // Buscar empresas para associar ao usuário
    const empresas = await kv.getByPrefix<any>('empresa:');
    
    console.log(`🔄 [autoProvisionUser] Total de empresas disponíveis: ${empresas?.length || 0}`);
    
    // Tentar encontrar empresa pelo domínio do email
    const emailDomain = authUser.email?.split('@')[1];
    let empresaAssociada = null;
    
    if (empresas && empresas.length > 0) {
      // Procurar empresa que tenha email similar
      empresaAssociada = empresas.find((emp: any) => {
        const empresaDomain = emp.email?.split('@')[1];
        return empresaDomain === emailDomain;
      });
      
      // Se não encontrou por domínio, NÃO USAR A PRIMEIRA EMPRESA!
      // Isso causa vazamento de dados (usuários vendo docs de outras empresas)
      if (!empresaAssociada) {
        console.log('⚠️ [autoProvisionUser] Empresa não encontrada por domínio. Mantendo usuário sem empresa para evitar vazamento de dados.');
        // empresaAssociada continua null
      } else {
        console.log('✅ [autoProvisionUser] Empresa encontrada por domínio:', empresaAssociada.nome);
      }
    } else {
      console.warn('⚠️ [autoProvisionUser] Nenhuma empresa disponível no sistema');
    }
    
    // ✅ Criar usuário com permissões básicas
    const novoUsuario: Usuario = {
      id: authUser.id,
      authUserId: authUser.id,
      email: authUser.email,
      nome: authUser.user_metadata?.nome || authUser.user_metadata?.name || authUser.email?.split('@')[0] || 'Usuário',
      empresaId: empresaAssociada?.id || null,
      nivel: empresaAssociada ? 'usuario' : 'usuario', // Usuário básico
      ativo: empresaAssociada ? true : false, // Ativo se tiver empresa, senão inativo
      modulosPermitidos: empresaAssociada ? ['faturacao', 'clientes', 'artigos'] : [],
      permissoes: {
        gerenciarUsuarios: false,
        concederPermissoes: false,
        visualizarLogs: false,
        exportarSAFT: false,
        configurarEmpresa: false,
        acessarPOS: false,
        consultarDocumentos: true,
        criarDocumentos: empresaAssociada ? true : false,
        editarDocumentos: empresaAssociada ? true : false,
        deletarDocumentos: false,
      },
      permissoesModulos: empresaAssociada ? {
        faturacao: {
          cotacao: { criar: true, editar: true, visualizar: true, deletar: false },
          factura: { criar: true, editar: true, visualizar: true, deletar: false },
          vd: { criar: true, editar: true, visualizar: true, deletar: false },
          nota: { criar: false, editar: false, visualizar: true, deletar: false },
          recibo: { criar: false, editar: false, visualizar: true, deletar: false },
          adiantamento: { criar: false, editar: false, visualizar: true, deletar: false },
        },
        clientes: { criar: true, editar: true, visualizar: true, deletar: false },
        artigos: { criar: true, editar: true, visualizar: true, deletar: false },
      } : {},
      dataCriacao: new Date().toISOString(),
      dataAtualizacao: new Date().toISOString(),
    };
    
    console.log('💾 [autoProvisionUser] Salvando usuário no KV Store...');
    console.log('💾 [autoProvisionUser] Chave primária: usuario:' + novoUsuario.id);
    console.log('💾 [autoProvisionUser] Chave email: usuario:email:' + novoUsuario.email);
    
    // ✅ CORREÇÃO: Salvar com DUAS chaves (como os outros usuários do sistema)
    await kv.set(`usuario:${novoUsuario.id}`, novoUsuario);
    await kv.set(`usuario:email:${novoUsuario.email}`, novoUsuario.id);
    
    console.log('✅ [autoProvisionUser] Usuário criado com sucesso:', {
      email: novoUsuario.email,
      nivel: novoUsuario.nivel,
      empresaId: novoUsuario.empresaId,
      ativo: novoUsuario.ativo,
    });
    
    if (!empresaAssociada) {
      console.warn('⚠️ [autoProvisionUser] ATENÇÃO: Usuário criado SEM empresa associada e INATIVO');
      console.warn('⚠️ [autoProvisionUser] Um administrador deve ativar e associar a uma empresa');
    }
    
    return novoUsuario;
    
  } catch (error) {
    console.error('❌ [autoProvisionUser] Erro ao criar usuário:', error);
    console.error('❌ [autoProvisionUser] Stack trace:', error instanceof Error ? error.stack : 'N/A');
    return null;
  }
}

// ========== VERIFICAR PERMISSAO ==========

function obterPermissoesGranularesUsuario(usuario: Usuario): any {
  return (usuario as any).permissoesModulos || (usuario as any).permissoesGranulares;
}

// ✅ As PermissionKey usadas nas rotas (ex: "faturacao.nota_credito.editar")
// usam underscore, mas o schema gravado em permissoesModulos (definido em
// tipos-permissoes-modulo.ts, no frontend) usa camelCase ("notaCredito").
// Sem esta traducao, a chave "nota_credito" nunca existe no objecto gravado
// e a permissao granular de Nota de Credito/Debito e sempre undefined —
// cai sempre no valor por omissao, ignorando por completo o que o admin
// configura no painel de permissoes.
const CHAVE_DOCUMENTO_GRANULAR: Record<string, string> = {
  nota_credito: 'notaCredito',
  nota_debito: 'notaDebito',
  factura_recibo: 'facturaRecibo',
  factura_proforma: 'facturaProforma',
};

function obterPermissaoGranularDocumento(
  usuario: Usuario,
  modulo: string,
  tipoDocumento: string,
  acao: string
): boolean | undefined {
  const chaveDocumento = CHAVE_DOCUMENTO_GRANULAR[tipoDocumento] || tipoDocumento;
  const permissoesGranulares = obterPermissoesGranularesUsuario(usuario);
  const documentoPermissoes = permissoesGranulares?.[modulo]?.[chaveDocumento];
  let permissao = documentoPermissoes?.[acao];

  // Dados antigos nao tinham a acao "aprovar/rejeitar" nas permissoes por modulo.
  // Nesses casos, aprovar/rejeitar cotacao segue a permissao de editar.
  if (permissao === undefined && ['aprovar', 'rejeitar'].includes(acao)) {
    permissao = documentoPermissoes?.editar;
  }

  return permissao;
}

function obterPermissaoLegada(usuario: Usuario, acao: string): boolean | undefined {
  const permissoes = (usuario as any).permissoes || {};
  const mapaLegado: Record<string, string[]> = {
    criar: ['criarDocumento', 'criarDocumentos'],
    editar: ['editarDocumentoPendente', 'editarDocumentos'],
    aprovar: ['editarDocumentoPendente', 'editarDocumentos'],
    rejeitar: ['editarDocumentoPendente', 'editarDocumentos'],
    deletar: ['deletarDocumento', 'deletarDocumentos'],
    anular: ['anularDocumento'],
    visualizar: ['consultarDocumentos', 'visualizarDocumentos'],
  };

  const chaves = mapaLegado[acao] || [];
  const chaveConfigurada = chaves.find((chave) => permissoes[chave] !== undefined);
  return chaveConfigurada ? permissoes[chaveConfigurada] === true : undefined;
}
/**
 * Verifica se usuário tem a permissão necessária
 * 
 * ✅ FASE 5 FIX: Agora verifica permissões granulares por módulo
 */
async function checkPermission(
  usuario: Usuario,
  permissionKey: PermissionKey
): Promise<PermissionCheckResult> {

  // ========== REGRA 1: VERIFICAR SE USUARIO ESTA ATIVO ==========

  if (!usuario.ativo) {
    return {
      allowed: false,
      motivo: "Usuário está inativo",
      usuario,
    };
  }

  // Requisito Financas/AT: admin/super_admin ja nao tem acesso
  // incondicional - tem acesso concedido por omissao (nunca bloqueado so
  // por falta de uma permissao gravada), mas uma permissao explicitamente
  // negada em permissoesModulos/permissoes e sempre respeitada, mesmo para
  // estes niveis (ver PermissoesModulosPanel.tsx para configurar).
  const nivelComAcessoAmplo =
    usuario.nivel === "super_admin" ||
    usuario.nivel === "admin" ||
    (usuario as any).nivel === "admin_empresa";

  // ========== REGRA 2: VERIFICAR PERMISSAO GRANULAR ==========

  // FASE 5 FIX: Parse da permissao granular (formato: "modulo.tipoDocumento.acao")
  // Exemplo: "faturacao.cotacao.criar" -> modulo=faturacao, tipo=cotacao, acao=criar
  const parts = permissionKey.split(".");

  if (parts.length !== 3) {
    // Permissoes do sistema (nao seguem o padrao modulo.tipo.acao)
    // Exemplo: "menu.config_empresa", "sistema.gerenciar_usuarios"
    const permissoesSistemaMap: Record<string, keyof Usuario["permissoes"]> = {
      "menu.config_empresa": "configurarEmpresa",
      "menu.permissoes_utilizadores": "concederPermissoes",
      "menu.logs_auditoria": "visualizarLogs",
      "menu.exportar_saft": "exportarSAFT",
      "menu.migrar_dados": "configurarEmpresa",
      "menu.gestao_modulos": "configurarEmpresa",
      "sistema.gerenciar_usuarios": "gerenciarUsuarios",
      "sistema.conceder_permissoes": "concederPermissoes",
      "sistema.visualizar_logs": "visualizarLogs",
      "sistema.configurar_empresa": "configurarEmpresa",
    };

    const mappedPermission = permissoesSistemaMap[permissionKey];

    if (!mappedPermission) {
      console.warn(`[checkPermission] Permissao desconhecida: ${permissionKey}`);
      return {
        allowed: false,
        motivo: `Permissao '${permissionKey}' nao esta mapeada no sistema`,
        usuario,
      };
    }

    const valorGravado = (usuario as any).permissoes?.[mappedPermission];
    const hasPermission = nivelComAcessoAmplo ? valorGravado !== false : valorGravado === true;

    return {
      allowed: hasPermission,
      motivo: hasPermission ? "Permissao de sistema concedida" : `Usuario nao possui a permissao '${permissionKey}'`,
      usuario,
    };
  }

  // Permissao granular (formato: modulo.tipo.acao)
  const [modulo, tipoDocumento, acao] = parts;

  const permissaoGranular = obterPermissaoGranularDocumento(usuario, modulo, tipoDocumento, acao);

  if (permissaoGranular === undefined) {
    if (nivelComAcessoAmplo) {
      // Administradores tem acesso documental concedido por omissao quando
      // nao ha uma permissao explicita gravada - nunca um bypass
      // incondicional (uma permissao explicitamente negada, tratada acima
      // no ramo "permissaoGranular !== undefined" mais abaixo, e sempre
      // respeitada mesmo para estes niveis).
      return {
        allowed: true,
        motivo: `Permissao documental concedida por omissao a administrador (${permissionKey})`,
        usuario,
      };
    }

    // Dados de RH (inclui salario base) nunca herdam das flags legadas
    // genericas (criarDocumentos/consultarDocumentos, pensadas para
    // documentos fiscais) — um utilizador so ve/edita RH se a permissao
    // granular "rh.colaborador.*" estiver explicitamente concedida.
    // Utilizadores existentes, criados antes deste modulo existir, nao tem
    // a chave "rh" no seu permissoesModulos e por omissao ficam sem acesso.
    if (modulo === "rh") {
      return {
        allowed: false,
        motivo: `Permissao de RH '${permissionKey}' requer concessao explicita (sem fallback legado)`,
        usuario,
      };
    }

    // ✅ Requisito Financas/AT: um tipo de documento adicionado ao schema
    // DEPOIS desta conta ter sido criada/gravada (ex: "vd", ou mais
    // recentemente "facturaRecibo"/"facturaProforma") fica simplesmente
    // ausente do permissoesModulos guardado - sem este fallback o
    // utilizador ficava banido desse documento inteiro ("Forbidden" mesmo
    // em "visualizar") ate um admin abrir e voltar a gravar as permissoes
    // desse utilizador no painel (so ai o merge do frontend preenche a
    // chave em falta). Isso e inconsistente com "conceder permissao entra
    // logo em vigor", que ja funciona para os documentos mais antigos do
    // schema (ex: cotacao). So se aplica quando o MODULO ja existe no
    // registo do utilizador (prova que a conta ja usa o sistema granular)
    // mas falta esta chave especifica - a mesma omissao do frontend
    // (tipos-permissoes-modulo.ts, PERMISSOES_DOCUMENTO_USUARIO): criar/
    // editar/visualizar concedidos, deletar/anular negados, ate o admin
    // restringir explicitamente.
    const chaveDocumentoOmissao = CHAVE_DOCUMENTO_GRANULAR[tipoDocumento] || tipoDocumento;
    const permissoesGranularesUsuario = obterPermissoesGranularesUsuario(usuario);
    const moduloJaConfigurado = permissoesGranularesUsuario?.[modulo];
    if (moduloJaConfigurado && moduloJaConfigurado[chaveDocumentoOmissao] === undefined) {
      const permitidoPorOmissao = acao !== "deletar" && acao !== "anular";
      return {
        allowed: permitidoPorOmissao,
        motivo: `Documento '${tipoDocumento}' ainda nao configurado explicitamente para este usuario — omissao aplicada (${acao})`,
        usuario,
      };
    }

    const permissaoLegada = obterPermissaoLegada(usuario, acao);
    if (permissaoLegada !== undefined) {
      return {
        allowed: permissaoLegada,
        motivo: permissaoLegada
          ? `Permissao legada concedida para '${permissionKey}'`
          : `Usuario nao possui permissao legada para '${permissionKey}'`,
        usuario,
      };
    }

    console.warn(`[checkPermission] Permissao granular nao configurada:`, {
      usuario: usuario.email,
      modulo,
      tipoDocumento,
      acao,
    });

    return {
      allowed: false,
      motivo: `Permissao granular '${permissionKey}' nao configurada para este usuario`,
      usuario,
    };
  }

  const hasPermission = permissaoGranular === true;

  return {
    allowed: hasPermission,
    motivo: hasPermission
      ? `Permissao granular concedida (${modulo} -> ${tipoDocumento} -> ${acao})`
      : `Usuario nao possui a permissao granular '${permissionKey}'`,
    usuario,
  };
}
// ========== MIDDLEWARE ==========

/**
 * 🆕 Extrai dados do usuário autenticado da requisição
 * Retorna: { id, nome, email } ou null se token inválido
 */
export async function getUserFromRequest(c: Context): Promise<{
  id: string;
  nome: string;
  email: string;
  empresaId?: string | null;
  nivel?: string;
} | null> {
  try {
    console.log('🔍 [getUserFromRequest] Iniciando extração de dados do usuário');
    
    const userToken = c.req.header('X-User-Token');
    
    console.log('🔍 [getUserFromRequest] X-User-Token presente:', !!userToken);
    
    if (!userToken) {
      console.warn('⚠️ [getUserFromRequest] Token não fornecido');
      return null;
    }
    
    console.log('🔍 [getUserFromRequest] Carregando usuário do token...');
    const usuario = await loadUserFromToken(userToken);
    
    console.log('🔍 [getUserFromRequest] Usuário carregado:', usuario ? {
      id: usuario.id,
      nome: usuario.nome,
      email: usuario.email
    } : 'null');
    
    if (!usuario) {
      console.warn('⚠️ [getUserFromRequest] Usuário não encontrado para o token');
      return null;
    }
    
    const resultado = {
      id: usuario.id,
      nome: usuario.nome,
      email: usuario.email,
      empresaId: usuario.empresaId,
      nivel: usuario.nivel,
    };
    
    console.log('✅ [getUserFromRequest] Dados extraídos com sucesso:', resultado);
    return resultado;
  } catch (error) {
    console.error('❌ [getUserFromRequest] Erro ao extrair usuário:', error);
    return null;
  }
}

/**
 * Middleware Hono que requer permissão específica
 * 
 * @param permissionKey - Chave da permissão necessária (ex: 'faturacao.factura.criar')
 * @returns Middleware function para Hono
 */
export function requirePermission(permissionKey: PermissionKey) {
  return async (c: Context, next: Next) => {
    const startTime = Date.now();

    console.log(`🔐 [requirePermission] Verificando permissão: ${permissionKey}`);
    console.log(`🔐 [requirePermission] URL: ${c.req.url}`);
    console.log(`🔐 [requirePermission] Método: ${c.req.method}`);
    console.log(`🔐 [requirePermission] Path: ${c.req.path}`);
    
    // ========== 1. EXTRAIR TOKEN DO USUÁRIO ==========
    
    // ✅ FIX: Buscar token do usuário no header customizado X-User-Token
    // (O header Authorization contém publicAnonKey para passar pelo middleware do Supabase)
    const userToken = c.req.header('X-User-Token');
    
    console.log(`🔐 [requirePermission] X-User-Token header presente: ${!!userToken}`);
    
    if (!userToken) {
      console.error('❌ [requirePermission] Token de usuário não fornecido no header X-User-Token');
      console.error(`❌ [requirePermission] Path que tentou acessar: ${c.req.path}`);
      
      return c.json({
        error: 'Unauthorized',
        message: 'Token de autenticação do usuário não fornecido',
        code: 'NO_USER_TOKEN',
      }, 401);
    }

    console.log(`🔐 [requirePermission] Token do usuário extraído (comprimento): ${userToken.length}`);

    // ========== 2. CARREGAR USUÁRIO ==========

    const usuario = await loadUserFromToken(userToken);

    if (!usuario) {
      console.error('❌ [requirePermission] Usuário não encontrado ou token inválido');
      
      return c.json({
        error: 'Unauthorized',
        message: 'Usuário não autenticado',
        code: 'INVALID_USER',
      }, 401);
    }

    // ========== 3. VERIFICAR PERMISSÃO ==========

    const checkResult = await checkPermission(usuario, permissionKey);

    const duration = Date.now() - startTime;

    // ========== 4. LOG ESTRUTURADO ==========

    const logData = {
      timestamp: new Date().toISOString(),
      permissao: permissionKey,
      usuario: {
        id: usuario.id,
        email: usuario.email,
        nivel: usuario.nivel,
        ativo: usuario.ativo,
      },
      resultado: checkResult.allowed ? 'PERMITIDO' : 'NEGADO',
      motivo: checkResult.motivo,
      duracao: `${duration}ms`,
      rota: c.req.path,
      metodo: c.req.method,
    };

    if (checkResult.allowed) {
      console.log('✅ [requirePermission] PERMITIDO:', logData);
    } else {
      console.warn('❌ [requirePermission] NEGADO:', logData);
    }

    // ========== 5. DECISÃO ==========

    if (!checkResult.allowed) {
      return c.json({
        error: 'Forbidden',
        message: checkResult.motivo,
        code: 'PERMISSION_DENIED',
        permission: permissionKey,
      }, 403);
    }

    // ========== 6. ANEXAR USUÁRIO AO CONTEXTO ==========

    // Anexar usuário ao contexto do Hono para uso no handler
    c.set('user', usuario);

    // ========== 7. CONTINUAR PARA HANDLER ==========

    await next();
  };
}

/**
 * Middleware que requer ALGUMA das permissões especificadas
 */
export function requireAnyPermission(...permissionKeys: PermissionKey[]) {
  return async (c: Context, next: Next) => {
    console.log(`🔐 [requireAnyPermission] Verificando permissões: ${permissionKeys.join(', ')}`);

    const userToken = c.req.header('X-User-Token');
    
    if (!userToken) {
      return c.json({
        error: 'Unauthorized',
        message: 'Token de autenticação não fornecido',
        code: 'NO_USER_TOKEN',
      }, 401);
    }

    const usuario = await loadUserFromToken(userToken);

    if (!usuario) {
      return c.json({
        error: 'Unauthorized',
        message: 'Usuário não autenticado',
        code: 'INVALID_USER',
      }, 401);
    }

    // Verificar se tem ALGUMA das permissões
    const checks = await Promise.all(
      permissionKeys.map(key => checkPermission(usuario, key))
    );

    const hasAnyPermission = checks.some(check => check.allowed);

    if (!hasAnyPermission) {
      console.warn('❌ [requireAnyPermission] NEGADO - Nenhuma das permissões encontrada');
      
      return c.json({
        error: 'Forbidden',
        message: 'Você não possui nenhuma das permissões necessárias',
        code: 'PERMISSION_DENIED',
        permissions: permissionKeys,
      }, 403);
    }

    console.log('✅ [requireAnyPermission] PERMITIDO');

    c.set('user', usuario);
    await next();
  };
}

/**
 * Middleware que requer TODAS as permissões especificadas
 */
export function requireAllPermissions(...permissionKeys: PermissionKey[]) {
  return async (c: Context, next: Next) => {
    console.log(`🔐 [requireAllPermissions] Verificando permissões: ${permissionKeys.join(', ')}`);

    const userToken = c.req.header('X-User-Token');
    
    if (!userToken) {
      return c.json({
        error: 'Unauthorized',
        message: 'Token de autenticação não fornecido',
        code: 'NO_USER_TOKEN',
      }, 401);
    }

    const usuario = await loadUserFromToken(userToken);

    if (!usuario) {
      return c.json({
        error: 'Unauthorized',
        message: 'Usuário não autenticado',
        code: 'INVALID_USER',
      }, 401);
    }

    // Verificar se tem TODAS as permissões
    const checks = await Promise.all(
      permissionKeys.map(key => checkPermission(usuario, key))
    );

    const deniedPermissions = checks
      .filter(check => !check.allowed)
      .map((_, index) => permissionKeys[index]);

    if (deniedPermissions.length > 0) {
      console.warn('❌ [requireAllPermissions] NEGADO - Faltam permissões:', deniedPermissions);
      
      return c.json({
        error: 'Forbidden',
        message: 'Você não possui todas as permissões necessárias',
        code: 'PERMISSION_DENIED',
        missingPermissions: deniedPermissions,
      }, 403);
    }

    console.log('✅ [requireAllPermissions] PERMITIDO');

    c.set('user', usuario);
    await next();
  };
}

/**
 * Middleware opcional que apenas anexa usuário ao contexto
 * Não bloqueia se não tiver permissão
 */
export async function attachUser(c: Context, next: Next) {
  const authHeader = c.req.header('Authorization');
  
  if (authHeader && authHeader.startsWith('Bearer ')) {
    const token = authHeader.substring(7);
    const usuario = await loadUserFromToken(token);
    
    if (usuario) {
      c.set('user', usuario);
    }
  }

  await next();
}

export async function verificarEscopoEmpresaRequest(
  c: Context,
  empresaId: string | null | undefined,
): Promise<{ permitido: boolean; status: number; error?: string; usuario?: any }> {
  const empresaAlvo = String(empresaId || '').trim();
  if (!empresaAlvo) {
    return { permitido: false, status: 400, error: 'ID da empresa nao fornecido' };
  }

  let usuario = typeof c.get === 'function' ? c.get('user') : null;
  if (!usuario) {
    const userToken = c.req.header('X-User-Token');
    if (!userToken) {
      return { permitido: false, status: 401, error: 'Utilizador nao autenticado' };
    }
    usuario = await loadUserFromToken(userToken);
  }

  if (!usuario || usuario.ativo === false) {
    return { permitido: false, status: 401, error: 'Utilizador nao autenticado ou inactivo' };
  }

  const nivel = String(usuario.nivel || '').trim().toLowerCase();
  if (nivel === 'super_admin' || nivel === 'superadmin_tonline') {
    return { permitido: true, status: 200, usuario };
  }

  if (!usuario.empresaId || String(usuario.empresaId) !== empresaAlvo) {
    return {
      permitido: false,
      status: 403,
      error: 'O utilizador nao pertence a empresa deste documento',
      usuario,
    };
  }

  return { permitido: true, status: 200, usuario };
}

export function requirePermissionFromBody(
  resolvePermission: (body: any) => PermissionKey,
) {
  return async (c: Context, next: Next) => {
    // ✅ O Hono já cacheia o resultado de c.req.json() por pedido — não
    // sobrescrever c.req.bodyCache (estrutura interna do Hono). Fazê-lo
    // corrompe qualquer c.req.json() chamado depois no handler final com o
    // erro "bodyCache[anyCachedKey].then is not a function".
    let body: any = {};
    try {
      body = await c.req.json();
    } catch (_error) {
      body = {};
    }

    const permissionKey = resolvePermission(body);
    return await requirePermission(permissionKey)(c, next);
  };
}
