require 'rails_helper'

# O catálogo é a fonte única de "o que dá para liberar". Estas travas existem
# porque um erro aqui não aparece na tela: uma chave escrita errado no
# PADRAO_POR_ROLE simplesmente não bate com nada e tira acesso de todo um papel
# em silêncio.
RSpec.describe Permissao do
  describe 'catálogo' do
    it 'toda chave segue o padrão area.acao e pertence a um grupo declarado' do
      described_class::TODAS.each do |chave, cfg|
        expect(chave.count('.')).to eq(1), "#{chave} fora do padrão area.acao"
        expect(described_class::GRUPOS).to have_key(cfg[:grupo]), "#{chave}: grupo #{cfg[:grupo]} não existe"
        expect(cfg[:label]).to be_present
        expect(cfg[:descricao]).to be_present, "#{chave} sem descrição (é o texto que o ADM lê na tela)"
      end
    end

    it 'por_grupo cobre todas as chaves' do
      total = described_class.por_grupo.values.sum(&:size)
      expect(total).to eq(described_class.chaves.size)
    end

    it 'filtrar descarta chave inexistente e repetida' do
      expect(described_class.filtrar(['consolidacao.ver', 'nao.existe', 'consolidacao.ver']))
        .to eq(['consolidacao.ver'])
    end
  end

  describe 'PADRAO_POR_ROLE' do
    it 'só usa chaves que existem no catálogo' do
      described_class::PADRAO_POR_ROLE.each do |role, lista|
        next if lista == :todas

        lista.each do |chave|
          expect(described_class).to be_existe(chave), "#{role} referencia chave inexistente: #{chave}"
        end
      end
    end

    it 'admin recebe o catálogo inteiro' do
      expect(described_class.do_role('admin')).to match_array(described_class.chaves)
    end

    # O fallback é o que mantém o comportamento de hoje para quem ainda não tem
    # perfil. Se estes pares mudarem, alguém perde acesso no dia do deploy.
    it 'reproduz pode_consolidar? e pode_ver_config? de cada papel' do
      {
        'admin'     => [true,  true],
        'gerente'   => [true,  true],
        'operador'  => [true,  false],
        'motorista' => [false, false],
        'externo'   => [false, false]
      }.each do |role, (consolidar, config)|
        chaves = described_class.do_role(role)
        expect(chaves.include?('consolidacao.ver')).to eq(consolidar), "#{role}: consolidar"
        expect(chaves.include?('admin.configuracoes')).to eq(config),  "#{role}: config"
      end
    end

    # As duas mudanças de comportamento deliberadas desta entrega.
    it 'externo não enxerga o financeiro (era o furo do skip_authorization)' do
      expect(described_class.do_role('externo')).not_to include('dashboard.financeiro')
    end

    it 'operador não enxerga a auditoria (o menu nunca ofereceu)' do
      expect(described_class.do_role('operador')).not_to include('admin.auditoria')
    end

    it 'motorista não usa permissão — o acesso dele é por tipo de conta' do
      expect(described_class.do_role('motorista')).to be_empty
    end
  end
end
