# app/jobs/detectar_mudancas_operacao_job.rb
#
# Compara os números de cada operação com o retrato anterior (OperacaoSnapshot)
# e dispara `operacao_alterada` no que mudou.
#
# POR QUE VARREDURA e não gatilho no código: a maior parte das mudanças da
# operação NÃO passa por aqui — ela acontece no SimpliRoute e chega pelo sync do
# espelho, que é read-only do nosso lado. Sem comparar retratos, "o que mudou"
# seria só o que o próprio sistema editou, que é a minoria dos casos.
#
# A PRIMEIRA execução de cada operação só grava o retrato e não avisa nada: sem
# retrato anterior, toda operação existente pareceria "nova" e o primeiro deploy
# dispararia uma mensagem por operação cadastrada.
class DetectarMudancasOperacaoJob < ApplicationJob
  queue_as :default

  def perform
    return unless EventoNotificacao.ativos.exists?(gatilho: 'operacao_alterada')

    Operacao.nomes_validos.each { |tabela| verificar(tabela) }
  rescue StandardError => e
    Rails.logger.error("[MudancasOperacao] #{e.class}: #{e.message}")
  end

  private

  def verificar(tabela)
    atuais   = contar(tabela)
    snapshot = OperacaoSnapshot.para(tabela)

    if snapshot.new_record?
      snapshot.registrar!(atuais)
      return
    end

    diferenca = snapshot.diferenca(atuais)
    return if diferenca.empty?

    Notificacao::Gatilhos.operacao_alterada(
      operacao: Operacao.label(tabela),
      o_que_mudou: OperacaoSnapshot.descrever(diferenca)
    )
    snapshot.registrar!(atuais)
  rescue StandardError => e
    # Uma operação problemática não pode impedir a varredura das demais.
    Rails.logger.error("[MudancasOperacao] #{tabela}: #{e.class}: #{e.message}")
  end

  # Sem filtro de data: a comparação é do estado ATUAL da operação inteira, que
  # é o que muda quando uma NF entra, sai ou troca de status.
  #
  # ⚠️ CUSTO: OperacaoMetricas carrega as visitas da operação em memória para
  #    deduplicar por NF. Uma operação mensal tem alguns milhares de linhas, e o
  #    job varre TODAS as tabelas a cada execução (8×/dia pelo schedule). É o
  #    preço de reusar a mesma contagem do dashboard em vez de escrever um SQL
  #    paralelo que divergiria dele. Se passar a incomodar, o caminho é restringir
  #    a varredura às operações do mês corrente e do anterior — as antigas não
  #    mudam mais.
  def contar(tabela)
    m = Analytics::OperacaoMetricas.new(tabelas: [tabela])
    { total_notas: m.total, entregues: m.sucesso,
      nao_entregues: m.recusas, pendentes: m.pendentes }
  end
end
