# app/services/notificacao/gatilhos.rb
#
# Os pontos do sistema que DISPARAM um evento de notificação. Cada método monta
# o contexto das {{variaveis}} daquele gatilho e entrega ao Despachante.
#
# Existe para que o código de negócio (consolidação, edição de lançamento, jobs)
# tenha UMA linha de chamada, sem saber de template, canal ou destinatário — e
# para que a lista de variáveis que o editor oferece (Notificacao::Variaveis)
# tenha um par exato aqui. Variável anunciada na tela e nunca preenchida sai como
# vazio na mensagem, o que é pior do que não existir.
#
# NADA aqui levanta: uma notificação não pode derrubar um fechamento nem uma
# edição de lançamento. O Despachante já engole, e os métodos que montam o
# contexto também.
module Notificacao
  module Gatilhos
    module_function

    # Valor do motorista mudou DEPOIS do fechamento (lançamento editado,
    # desconto aplicado, pilar remarcado). Em rascunho o valor muda a cada
    # clique do wizard — avisar ali seria spam, não informação.
    def valor_alterado(consolidacao, consolidacao_motorista, anterior:)
      return unless consolidacao.finalizada?

      atual = consolidacao_motorista.valor_total.to_f
      return if anterior.to_f == atual

      Despachante.disparar_gatilho(
        gatilho: 'valor_alterado',
        dados: Variaveis.comuns_reais.merge(
          'motorista'    => consolidacao_motorista.motorista_nome,
          'consolidacao' => consolidacao.nome,
          'periodo'      => periodo(consolidacao.data_inicio, consolidacao.data_fim),
          'valor'        => moeda(atual),
          'entregas'     => contar_entregas(consolidacao, consolidacao_motorista).to_s,
          'link_painel'  => link_painel,
          'o_que_mudou'  => "Valor passou de #{moeda(anterior)} para #{moeda(atual)}"
        ),
        assunto: "Valor alterado — #{consolidacao_motorista.motorista_nome}",
        corpo: "⚠️ O valor de #{consolidacao_motorista.motorista_nome} em #{consolidacao.nome} " \
               "passou de #{moeda(anterior)} para #{moeda(atual)}.",
        # O próprio motorista é parte interessada: o valor DELE mudou depois de
        # fechado. Fica sob o `notificar_envolvido` do evento, então o ADM pode
        # desligar sem perder o aviso à diretoria.
        envolvido: motorista_usuario(consolidacao_motorista)
      )
    rescue StandardError => e
      Rails.logger.error("[Gatilhos] valor_alterado: #{e.class}: #{e.message}")
    end

    # Dados da operação mudaram. Duas origens, os dois caminham para cá:
    #   - edição de lançamento no SimpliRoute feita por dentro do sistema;
    #   - varredura periódica que compara o espelho com o retrato anterior
    #     (DetectarMudancasOperacaoJob) — é por onde chega a maioria, já que o
    #     espelho sincroniza mudanças feitas fora daqui.
    def operacao_alterada(operacao:, o_que_mudou:, nf: nil)
      Despachante.disparar_gatilho(
        gatilho: 'operacao_alterada',
        dados: Variaveis.comuns_reais.merge(
          'operacao'    => operacao.to_s,
          'o_que_mudou' => o_que_mudou.to_s,
          'nf'          => nf.to_s
        ),
        assunto: "Alteração na operação #{operacao}",
        corpo: "🔄 #{operacao}: #{o_que_mudou}#{nf.present? ? " (NF #{nf})" : ''}"
      )
    rescue StandardError => e
      Rails.logger.error("[Gatilhos] operacao_alterada: #{e.class}: #{e.message}")
    end

    # Resumo periódico de um evento `agendado`.
    def resumo_agendado(evento, inicio:, fim:)
      numeros = Analytics::ResumoOperacao.new(inicio: inicio, fim: fim).numeros

      Despachante.disparar(
        chave: evento.chave,
        dados: Variaveis.comuns_reais.merge(numeros).merge(
          'periodo' => periodo(inicio, fim)
        ),
        assunto: "Resumo da operação — #{periodo(inicio, fim)}",
        corpo: corpo_resumo(numeros, inicio, fim)
      )
    rescue StandardError => e
      Rails.logger.error("[Gatilhos] resumo_agendado #{evento.chave}: #{e.class}: #{e.message}")
    end

    # ── Auxiliares ─────────────────────────────────────────────

    def corpo_resumo(numeros, inicio, fim)
      "📊 Resumo da operação — #{periodo(inicio, fim)}\n" \
      "• Entregues: #{numeros['entregues']}\n" \
      "• Não entregues: #{numeros['recusas']}\n" \
      "• Em aberto: #{numeros['pendentes']}\n" \
      "• Retentativas: #{numeros['retentativas']}\n" \
      "• Notas fora da operação: #{numeros['fora_operacao']}"
    end

    def periodo(inicio, fim)
      "#{inicio&.strftime('%d/%m/%Y')} a #{fim&.strftime('%d/%m/%Y')}"
    end

    def link_painel
      "https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
    end

    # Mesma busca do NotificacaoService (casa pelo nome, que é o que a
    # consolidação guarda). Só roda em consolidação finalizada, então o custo
    # por recálculo é irrelevante.
    def motorista_usuario(consolidacao_motorista)
      User.motorista.ativos.find_by('LOWER(nome) = ?', consolidacao_motorista.motorista_nome.to_s.downcase)
    rescue StandardError
      nil
    end

    def contar_entregas(consolidacao, consolidacao_motorista)
      consolidacao.consolidacao_entregas
                  .where(motorista_nome: consolidacao_motorista.motorista_nome)
                  .where.not(tipo: :desconto)
                  .count
    rescue StandardError
      nil
    end

    # Formatação vive em Notificacao::Formatador (era copiada aqui e no
    # NotificacaoService; com o catálogo de variáveis seriam três cópias).
    def moeda(valor) = Formatador.moeda(valor)
  end
end
