# app/services/notificacao_service.rb
#
# Envia notificações aos motoristas quando uma consolidação é finalizada ou
# quando o pagamento é efetuado.
#
# Canais e credenciais vêm de ConfiguracaoNotificacao (tela /admin/
# configuracao_notificacao), com fallback para o .env.
#
# Falhas de envio NUNCA quebram o fluxo de finalização — apenas logam. Isso é
# intencional: um SMTP fora do ar não pode impedir o fechamento de um pagamento.
# Para DIAGNOSTICAR o envio, use os botões de teste da tela, que usam
# Notificacao::TesteEmail / Notificacao::TesteWhatsapp e mostram o erro real.
class NotificacaoService
  EVENTOS = {
    fechado: { mailer: :pagamento_fechado,
               chave:  'consolidacao_finalizada',
               emoji:  '🚚',
               titulo: 'Seu pagamento de entregas foi fechado.',
               cta:    'Acesse seu painel para baixar o extrato:' },
    pago:    { mailer: :pagamento_efetuado,
               chave:  'pagamento_efetuado',
               emoji:  '✅',
               titulo: 'Seu pagamento foi efetuado.',
               cta:    'Acesse seu painel para conferir:' }
  }.freeze

  def self.notificar_finalizacao(consolidacao)
    new(consolidacao).notificar_todos
  end

  # Avisa UM motorista de que o pagamento dele foi efetuado.
  def self.notificar_pagamento(consolidacao, consolidacao_motorista)
    new(consolidacao).enviar_aviso_pagamento(consolidacao_motorista)
  end

  def initialize(consolidacao)
    @consolidacao = consolidacao
    @config       = ConfiguracaoNotificacao.instancia
  end

  def notificar_todos
    @consolidacao.consolidacao_motoristas.ativos.each { |cm| notificar(cm, :fechado) }
  end

  def enviar_aviso_pagamento(consolidacao_motorista)
    notificar(consolidacao_motorista, :pago)
  end

  private

  def notificar(cm, evento)
    user = motorista_de(cm)

    # Aviso pessoal ao motorista: continua com o e-mail formatado do
    # ConsolidacaoMailer (não vira texto puro) e passa a usar o provedor de
    # WhatsApp escolhido na tela — Baileys por QR ou Twilio.
    if user
      enviar_whatsapp(user, cm, evento) if @config.whatsapp_habilitado?
      enviar_email(user, cm, evento)    if @config.email_habilitado? && user.email.present?
    end

    # Cópia para os grupos que assinam este evento (diretoria, operação...).
    # `envolvido: nil` de propósito: o motorista já foi avisado acima e receberia
    # a mensagem duas vezes.
    avisar_grupos(cm, evento, user)
  end

  # O corpo aqui é o mesmo texto do WhatsApp — na etapa do editor de blocos ele
  # passa a vir do template configurado pelo ADM.
  def avisar_grupos(cm, evento, user)
    evt = EVENTOS.fetch(evento)
    Notificacao::Despachante.disparar_gatilho(
      gatilho: evt[:chave],
      dados: variaveis(cm, user),
      assunto: "#{evt[:titulo]} — #{@consolidacao.nome}",
      corpo: mensagem_para_grupos(cm, evento, user)
    )
  end

  # Contexto das {{variaveis}} do editor de blocos. As chaves são as mesmas de
  # Notificacao::Variaveis::FECHAMENTO — é o que o ADM vê na paleta da tela.
  def variaveis(cm, user)
    Notificacao::Variaveis.comuns_reais.merge(
      'motorista'    => user&.nome.presence || cm.motorista_nome,
      'consolidacao' => @consolidacao.nome,
      'periodo'      => "#{l_data(@consolidacao.data_inicio)} a #{l_data(@consolidacao.data_fim)}",
      'valor'        => moeda(cm.valor_total),
      # ConsolidacaoMotorista não guarda contagem — só valor_total. As entregas
      # do motorista são as linhas classificadas na consolidação (mesma fonte do
      # #recalcular_valor), descontando os lançamentos de desconto, que não são
      # entregas.
      'entregas'     => entregas_do_motorista(cm).to_s,
      'link_painel'  => "https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
    )
  end

  def l_data(data)
    data&.strftime('%d/%m/%Y').to_s
  end

  def entregas_do_motorista(cm)
    @consolidacao.consolidacao_entregas
                 .where(motorista_nome: cm.motorista_nome)
                 .where.not(tipo: :desconto)
                 .count
  rescue StandardError => e
    Rails.logger.warn("[Notificacao] contagem de entregas indisponível: #{e.class}: #{e.message}")
    nil
  end

  def mensagem_para_grupos(cm, evento, user)
    evt = EVENTOS.fetch(evento)
    "#{evt[:emoji]} #{evt[:titulo]}\n" \
    "👤 #{user&.nome || cm.motorista_nome}\n" \
    "📋 #{@consolidacao.nome}\n" \
    "💰 Valor: #{moeda(cm.valor_total)}"
  end

  def motorista_de(cm)
    User.motorista.ativos.find_by('LOWER(nome) = ?', cm.motorista_nome.downcase)
  end

  def enviar_whatsapp(user, cm, evento)
    # O telefone no cadastro pode estar como "(11) 92005-1157"; a normalização
    # para E.164 acontece dentro de Notificacao::Whatsapp — mandar o texto cru
    # devolve erro de destino inválido que o rescue esconderia.
    destino = ConfiguracaoNotificacao.normalizar_telefone(user.telefone)
    return if destino.blank?

    texto = mensagem(user, cm, evento)
    envio = registrar_envio(evento, canal: 'whatsapp', destino: destino, user: user, corpo: texto)

    resposta = Notificacao::Whatsapp.enviar(para: destino, texto: texto, config: @config)
    if resposta.ok?
      envio&.marcar_enviado!
      Rails.logger.info("[Notificacao] WhatsApp (#{evento}) enviado para #{user.nome}")
    else
      envio&.marcar_falha!(resposta.erro)
      Rails.logger.error("[Notificacao] Falha WhatsApp (#{evento}) #{user.nome}: #{resposta.erro}")
    end
  end

  def enviar_email(user, cm, evento)
    evt   = EVENTOS.fetch(evento)
    envio = registrar_envio(evento, canal: 'email', destino: user.email, user: user,
                            corpo: mensagem(user, cm, evento), assunto: evt[:titulo])

    ConsolidacaoMailer.public_send(evt[:mailer], user, @consolidacao, cm).deliver_later
    # `deliver_later` só ENFILEIRA: marcar como enviado aqui significa "saiu do
    # nosso lado". Uma falha do SMTP aparece no log do Rails, não aqui.
    envio&.marcar_enviado!
    Rails.logger.info("[Notificacao] Email (#{evento}) agendado para #{user.email}")
  rescue StandardError => e
    envio&.marcar_falha!("#{e.class}: #{e.message}")
    Rails.logger.error("[Notificacao] Falha email (#{evento}) #{user.email}: #{e.class}: #{e.message}")
  end

  # Log do aviso pessoal. Nunca levanta: se a tabela ainda não existir (deploy
  # antes do migrate), o envio precisa seguir mesmo sem registro.
  def registrar_envio(evento, canal:, destino:, user:, corpo:, assunto: nil)
    NotificacaoEnvio.create!(
      evento_notificacao: evento_registrado(evento), user: user, canal: canal,
      destino: destino, assunto: assunto, corpo: corpo, status: 'pendente'
    )
  rescue StandardError => e
    Rails.logger.warn("[Notificacao] sem log de envio (#{e.class}: #{e.message})")
    nil
  end

  def evento_registrado(evento)
    @eventos_cache ||= {}
    @eventos_cache[evento] ||= EventoNotificacao.find_by(chave: EVENTOS.fetch(evento)[:chave])
  end

  def mensagem(user, cm, evento)
    evt = EVENTOS.fetch(evento)
    "Olá #{user.nome.split.first}! #{evt[:emoji]}\n" \
    "#{evt[:titulo]}\n" \
    "📋 #{@consolidacao.nome}\n" \
    "💰 Valor: #{moeda(cm.valor_total)}\n" \
    "#{evt[:cta]} https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
  end

  # Ver Notificacao::Formatador — implementação única.
  def moeda(valor) = Notificacao::Formatador.moeda(valor)
end
