require 'rails_helper'

RSpec.describe Consolidacao, type: :model do
  describe 'validação de período' do
    it 'rejeita data_fim anterior a data_inicio' do
      c = build(:consolidacao, data_inicio: Date.new(2026, 6, 10), data_fim: Date.new(2026, 6, 1))
      expect(c).not_to be_valid
      expect(c.errors[:data_fim]).to be_present
    end

    it 'aceita período válido' do
      expect(build(:consolidacao)).to be_valid
    end
  end

  describe '#recalcular_valor_total (before_save)' do
    it 'soma os valores dos motoristas da consolidação' do
      consolidacao = create(:consolidacao)
      create(:consolidacao_motorista, consolidacao: consolidacao, motorista_nome: 'A')
      create(:consolidacao_motorista, consolidacao: consolidacao, motorista_nome: 'B')
      consolidacao.consolidacao_motoristas.update_all(valor_total: 30)

      consolidacao.save!
      expect(consolidacao.reload.valor_total).to eq(60)
    end
  end

  describe '#finalizar!' do
    let(:consolidacao) { create(:consolidacao) }
    let(:gerente)      { create(:gerente) }

    it 'não finaliza quando há entregas não classificadas' do
      allow(consolidacao).to receive(:todas_entregas_classificadas?).and_return(false)
      expect(consolidacao.finalizar!(gerente)).to be_falsey
      expect(consolidacao.reload).to be_rascunho
    end

    it 'finaliza e registra finalizador quando tudo está classificado' do
      allow(consolidacao).to receive(:todas_entregas_classificadas?).and_return(true)
      consolidacao.finalizar!(gerente)
      consolidacao.reload
      expect(consolidacao).to be_finalizada
      expect(consolidacao.finalizado_por).to eq(gerente.id)
      expect(consolidacao.finalizado_em).to be_present
    end
  end

  describe '#arquivar!' do
    it 'marca deleted_at, status arquivada e registra quem arquivou' do
      gerente = create(:gerente)
      consolidacao = create(:consolidacao)
      consolidacao.arquivar!(gerente)
      consolidacao.reload
      expect(consolidacao).to be_arquivada
      expect(consolidacao.deleted_at).to be_present
      expect(consolidacao.arquivado_por).to eq(gerente.id)
      expect(consolidacao.arquivado_em).to be_present
      expect(consolidacao.arquivador).to eq(gerente)
    end
  end

  describe '#todas_entregas_classificadas? (gate por motorista)' do
    let(:consolidacao) { create(:consolidacao) }

    before do
      create(:consolidacao_motorista, consolidacao: consolidacao, motorista_nome: 'A')
      create(:consolidacao_motorista, consolidacao: consolidacao, motorista_nome: 'B')
    end

    it 'é falso quando UM motorista tem pendências, mesmo que outro tenha entregas de sobra' do
      allow(consolidacao).to receive(:entregas_elegiveis_count).and_return(2)
      # A: 0 classificadas | B: 4 classificadas. A soma agregada (4 >= 4) passaria,
      # mas a checagem por motorista deve reprovar.
      create_list(:consolidacao_entrega, 4, consolidacao: consolidacao, motorista_nome: 'B')
      expect(consolidacao.todas_entregas_classificadas?).to be false
    end

    it 'é verdadeiro quando cada motorista está completo' do
      allow(consolidacao).to receive(:entregas_elegiveis_count).and_return(1)
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'A')
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'B')
      expect(consolidacao.todas_entregas_classificadas?).to be true
    end

    it 'ignora motoristas sem entregas elegíveis (total zero)' do
      allow(consolidacao).to receive(:entregas_elegiveis_count).and_return(0)
      expect(consolidacao.todas_entregas_classificadas?).to be true
    end
  end

  describe '#classificadas_count (ignora apontamentos manuais)' do
    let(:consolidacao) { create(:consolidacao) }

    it 'conta entregas elegíveis e ignora as manuais (não infla o progresso)' do
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'A', tracking_id: 'T1')
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'A', tracking_id: 'T2')
      # Apontamento manual — fora do conjunto elegível do período.
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'A',
                                    tracking_id: 'T3', manual: true)

      expect(consolidacao.classificadas_count('A')).to eq(2)
    end

    it 'não ultrapassa o total elegível por causa de apontamentos (gate continua válido)' do
      create(:consolidacao_motorista, consolidacao: consolidacao, motorista_nome: 'A')
      allow(consolidacao).to receive(:entregas_elegiveis_count).and_return(1)
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'A', tracking_id: 'T1')
      create(:consolidacao_entrega, consolidacao: consolidacao, motorista_nome: 'A',
                                    tracking_id: 'T2', manual: true)

      expect(consolidacao.classificadas_count('A')).to eq(1)
      expect(consolidacao.todas_entregas_classificadas?).to be true
    end
  end

  describe '#adicionar_apontamento! (apontamento manual multi-tipo)' do
    let(:consolidacao) { create(:consolidacao) }
    let(:user)         { create(:gerente) }
    let(:entrega)      { Struct.new(:tracking_id, :driver).new('TRK-AV', 'Steferson Lucas') }

    before { allow(ConsolidacaoEntrega).to receive(:valor_para).and_return(15.0) }

    it 'inclui o motorista e cria um pilar manual por tipo, somando o valor' do
      consolidacao.adicionar_apontamento!(entrega, %w[entrega_normal bonus], user)

      cm = consolidacao.consolidacao_motoristas.find_by(motorista_nome: 'Steferson Lucas')
      expect(cm).to be_present

      pilares = consolidacao.consolidacao_entregas.where(tracking_id: 'TRK-AV')
      expect(pilares.count).to eq(2)
      expect(pilares.all?(&:manual?)).to be true
      expect(cm.reload.valor_total).to eq(30.0)
    end

    it 'é idempotente por (tracking, tipo) e exige ao menos um tipo válido' do
      consolidacao.adicionar_apontamento!(entrega, %w[entrega_normal], user)
      consolidacao.adicionar_apontamento!(entrega, %w[entrega_normal], user)
      expect(consolidacao.consolidacao_entregas.where(tracking_id: 'TRK-AV').count).to eq(1)

      expect { consolidacao.adicionar_apontamento!(entrega, [], user) }.to raise_error(ArgumentError)
    end
  end

  describe 'escopos de soft delete' do
    it 'separa ativas de arquivadas' do
      ativa     = create(:consolidacao)
      arquivada = create(:consolidacao)
      arquivada.arquivar!(create(:gerente))

      expect(Consolidacao.ativas).to include(ativa)
      expect(Consolidacao.ativas).not_to include(arquivada)
      expect(Consolidacao.arquivadas).to include(arquivada)
    end
  end
end
