# app/services/notificacao/teste_email.rb
#
# Dispara um e-mail de teste com as credenciais que ACABARAM de ser salvas e
# devolve o erro REAL traduzido para português. É o oposto do NotificacaoService,
# que engole as falhas de propósito para não derrubar o fechamento — aqui o
# objetivo é justamente mostrar o problema.
module Notificacao
  class TesteEmail
    def initialize(config = ConfiguracaoNotificacao.instancia, destinatario: nil, usuario: nil)
      @config       = config
      @destinatario = destinatario.presence || config.email_admin.presence
      @usuario      = usuario
    end

    def executar
      if @destinatario.blank?
        return Resultado.falha('Preencha o "E-mail do administrador" antes de enviar o teste.')
      end

      unless @config.smtp_pronto?
        return Resultado.falha('Marque "Ativar envio de e-mail" e preencha servidor, porta, ' \
                               'usuário e senha antes de testar.')
      end

      entrega = TesteMailer.teste(@destinatario, @config, @usuario)
      # development.rb define raise_delivery_errors = false e o mail() copia isso
      # para a mensagem — sem estas duas linhas o teste "passaria" em silêncio.
      entrega.message.raise_delivery_errors = true
      entrega.message.perform_deliveries    = true
      # NUNCA deliver_later: o adapter é :async (thread in-process) e a exceção
      # nunca voltaria para o flash.
      entrega.deliver_now

      Resultado.sucesso("E-mail de teste enviado para #{@destinatario}. " \
                        'Confira a caixa de entrada e também o spam.')
    rescue Net::SMTPAuthenticationError => e
      Resultado.falha('Usuário ou senha do SMTP recusados pelo servidor. No Gmail/Google ' \
                      'Workspace é preciso usar uma "Senha de app" de 16 caracteres, ' \
                      'não a senha da conta.', e.message)
    rescue Net::SMTPSyntaxError, Net::SMTPFatalError => e
      Resultado.falha("O servidor recusou a mensagem. Normalmente o remetente " \
                      "(#{@config.remetente_email.presence || @config.smtp_username}) precisa ser " \
                      'o mesmo usuário que autenticou.', e.message)
    rescue Net::SMTPServerBusy => e
      Resultado.falha('Servidor SMTP ocupado ou aplicando limite de envio. ' \
                      'Tente de novo em alguns minutos.', e.message)
    rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ETIMEDOUT => e
      Resultado.falha("Tempo esgotado ao conectar em #{@config.smtp_address}:#{@config.smtp_port}. " \
                      'A porta pode estar bloqueada pelo provedor ou pelo firewall — ' \
                      'tente 587 (STARTTLS) ou 465 (SSL).', e.message)
    rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
      Resultado.falha("Conexão recusada por #{@config.smtp_address}:#{@config.smtp_port}. " \
                      'Servidor ou porta incorretos.', e.message)
    rescue SocketError => e
      Resultado.falha("Não foi possível resolver o endereço \"#{@config.smtp_address}\". " \
                      'Confira a grafia do servidor.', e.message)
    rescue OpenSSL::SSL::SSLError => e
      Resultado.falha('Erro de TLS/SSL. A porta 465 exige SSL direto e a 587 exige STARTTLS — ' \
                      'confira se a porta escolhida bate com o servidor.', e.message)
    rescue Net::SMTPError, EOFError, IOError => e
      # Net::SMTPError é um módulo incluído nas classes acima; por isso vem
      # depois delas, como rede de segurança.
      Resultado.falha("O servidor SMTP interrompeu a conexão: #{e.message}", e.message)
    rescue StandardError => e
      Rails.logger.error("[TesteEmail] #{e.class}: #{e.message}\n#{e.backtrace&.first(5)&.join("\n")}")
      Resultado.falha("Falha inesperada ao enviar (#{e.class}).", e.message)
    end
  end
end
