require 'rails_helper'

# Trava a conta do modo de visualização "Por motorista" — a mesma que alimenta
# /consolidacoes?visao=motoristas (admin) e o painel do motorista. As duas telas
# usam ESTE service justamente para não poderem divergir.
RSpec.describe Analytics::TotaisPorMotorista do
  let(:inicio) { Date.new(2026, 6, 1) }
  let(:fim)    { Date.new(2026, 6, 30) }

  # Uma consolidação com um motorista e `qtd` lançamentos de `valor` cada. As
  # entregas vêm ANTES do ConsolidacaoMotorista porque é o before_save dele que
  # calcula valor_total a partir delas.
  def consolidar(motorista:, valor: 100.0, qtd: 1, status: :finalizada,
                 data_inicio: Date.new(2026, 6, 1), data_fim: Date.new(2026, 6, 30),
                 pago: false, arquivado: false)
    c = create(:consolidacao, status: status, data_inicio: data_inicio, data_fim: data_fim)
    qtd.times { create(:consolidacao_entrega, consolidacao: c, motorista_nome: motorista, valor_aplicado: valor) }
    cm = create(:consolidacao_motorista, consolidacao: c, motorista_nome: motorista)
    cm.update!(pago_em: Time.current, forma_pagamento: 'pix') if pago
    cm.arquivar!(nil) if arquivado
    [c, cm]
  end

  subject(:totais) { described_class.new(inicio: inicio, fim: fim) }

  it 'soma por motorista só as consolidações finalizadas do período' do
    consolidar(motorista: 'Carlos', valor: 100.0, qtd: 2)                  # 200
    consolidar(motorista: 'Carlos', valor: 50.0,  qtd: 1)                  # 50
    consolidar(motorista: 'Pedro',  valor: 30.0,  qtd: 1)                  # 30
    consolidar(motorista: 'Carlos', valor: 999.0, status: :rascunho)       # fora (rascunho)
    consolidar(motorista: 'Carlos', valor: 999.0,                          # fora (não cruza)
               data_inicio: Date.new(2026, 7, 1), data_fim: Date.new(2026, 7, 31))

    expect(totais.linhas.map { |l| [l[:motorista], l[:valor_total]] })
      .to eq([['Carlos', 250.0], ['Pedro', 30.0]])
    expect(totais.total_geral).to eq(280.0)
    expect(totais.total_consolidacoes).to eq(3)
  end

  # ── Recorte de datas: o MESMO do dashboard financeiro ───────────────────
  # Quando estes dois casos divergiam do dashboard, o operador via dois valores
  # diferentes para o mesmo motorista no mesmo período e lia como erro de conta.
  it 'inclui a consolidação que CRUZA o período (não precisa caber inteira)' do
    # 20/05 a 20/06: começa antes do filtro, termina dentro.
    consolidar(motorista: 'Carlos', valor: 100.0,
               data_inicio: Date.new(2026, 5, 20), data_fim: Date.new(2026, 6, 20))
    # 20/06 a 20/07: começa dentro, termina depois.
    consolidar(motorista: 'Carlos', valor: 40.0,
               data_inicio: Date.new(2026, 6, 20), data_fim: Date.new(2026, 7, 20))

    expect(totais.total_geral).to eq(140.0)
  end

  it 'inclui a consolidação de outro período PAGA dentro do período' do
    _, cm = consolidar(motorista: 'Carlos', valor: 80.0,
                       data_inicio: Date.new(2026, 4, 1), data_fim: Date.new(2026, 4, 30))
    cm.update!(pago_em: Time.zone.local(2026, 6, 10, 12, 0), forma_pagamento: 'pix')

    expect(totais.total_geral).to eq(80.0)
    expect(totais.total_pago).to eq(80.0)
  end

  it 'respeita o filtro de status (o mesmo select da lista)' do
    consolidar(motorista: 'Carlos', valor: 100.0)
    consolidar(motorista: 'Carlos', valor: 40.0, status: :rascunho)

    expect(totais.total_geral).to eq(100.0)  # default: só finalizadas
    expect(described_class.new(inicio: inicio, fim: fim, status: 'todos').total_geral).to eq(140.0)
    expect(described_class.new(inicio: inicio, fim: fim, status: 'rascunho').total_geral).to eq(40.0)
  end

  it 'busca parcial por nome do motorista (campo de busca da tela)' do
    consolidar(motorista: 'Carlos Matheus', valor: 100.0)
    consolidar(motorista: 'Pedro Martins', valor: 30.0)

    achou = described_class.new(inicio: inicio, fim: fim, busca: 'matheus')
    expect(achou.linhas.map { |l| l[:motorista] }).to eq(['Carlos Matheus'])
  end

  it 'separa pago de a receber' do
    consolidar(motorista: 'Carlos', valor: 100.0, pago: true)
    consolidar(motorista: 'Carlos', valor: 60.0)

    linha = totais.linhas.first
    expect(linha[:valor_pago]).to eq(100.0)
    expect(linha[:valor_pendente]).to eq(60.0)
    expect(totais.total_pago).to eq(100.0)
    expect(totais.total_pendente).to eq(60.0)
  end

  it 'ignora motorista arquivado (mesmo conjunto que a consolidação paga)' do
    consolidar(motorista: 'Carlos', valor: 100.0)
    consolidar(motorista: 'Carlos', valor: 70.0, arquivado: true)

    expect(totais.total_geral).to eq(100.0)
  end

  it 'lista as consolidações que compõem o total do motorista' do
    c1, = consolidar(motorista: 'Carlos', valor: 100.0)
    c2, = consolidar(motorista: 'Carlos', valor: 60.0, data_fim: Date.new(2026, 6, 15))
    consolidar(motorista: 'Pedro', valor: 30.0)

    composicao = totais.consolidacoes_de('Carlos')
    expect(composicao.map(&:consolidacao_id)).to match_array([c1.id, c2.id])
    expect(composicao.sum(&:valor_total)).to eq(160.0)
  end

  it 'recortado por motorista, só enxerga o dele (visão do painel do motorista)' do
    consolidar(motorista: 'Carlos', valor: 100.0)
    consolidar(motorista: 'Pedro',  valor: 30.0)

    meu = described_class.new(inicio: inicio, fim: fim, motorista: 'Carlos')
    expect(meu.total_geral).to eq(100.0)
    expect(meu.linhas.size).to eq(1)
  end

  it 'período sem fechamento fica vazio (e não quebra)' do
    vazio = described_class.new(inicio: Date.new(2026, 1, 1), fim: Date.new(2026, 1, 31))
    expect(vazio).to be_vazio
    expect(vazio.total_geral).to eq(0)
    expect(vazio.linhas).to eq([])
  end
end
