require 'erb'
require 'logger'
require 'time'
require 'hookworm-base'

module Hookworm
  class RogueCommitEmailNotifier
    attr_reader :cfg, :env

    def initialize(cfg, env = ENV)
      @cfg = cfg
      @env = env
    end

    def notify!(payload)
      safe_send_rogue_commit_email!(payload)
    end

    def safe_send_rogue_commit_email!(payload)
      send_rogue_commit_email!(payload)
      log.debug { "Sent rogue commit email to #{recipients}" }
    rescue => e
      log.error { "#{e.class.name} #{e.message}" }
      log.debug { e.backtrace.join("\n") }
      raise e
    end

    def send_rogue_commit_email!(payload)
      if recipients.empty?
        log.warn { 'No email recipients specified, so no emailing!' }
        return
      end

      email_body = render_email(payload)
      log.debug { "Email message:\n#{email_body}" }

      emailer.send_email(fromaddr, recipients, email_body)
    end

    def render_email(payload)
      EmailRenderContext.new(
        self, payload, rogue_commit_email_tmpl, hostname
      ).render
    end

    def rogue_commit_email_tmpl
      ERB.new(rogue_commit_email_tmpl_string)
    end

    def rogue_commit_email_tmpl_string
      File.read(File.expand_path('../rogue-commit-email-tmpl.erb', __FILE__))
    end

    def recipients
      @recipients ||= (cfg[:worm_flags][:email_recipients] || '').commasplit
    end

    def fromaddr
      @fromaddr ||= cfg[:worm_flags][:email_from_addr]
    end

    def hostname
      @hostname ||= (
        ENV['HOOKWORM_EMAIL_HOSTNAME'] || cfg[:worm_flags][:email_hostname]
      )
    end

    def watched_branches
      @watched_branches ||= (
        cfg[:worm_flags][:watched_branches] || ''
      ).commasplit
    end

    def watched_paths
      @watched_paths ||= (cfg[:worm_flags][:watched_paths] || '').commasplit
    end

    def emailer
      @emailer ||= Hookworm::Emailer.new(
        env['HOOKWORM_EMAIL_URI'] || cfg[:worm_flags][:email_uri],
        env['HOOKWORM_EMAIL_HELO'] || 'localhost'
      )
    end

    def log
      @log ||= Logger.new($stderr)
    end

    class EmailRenderContext
      def initialize(notifier, payload, tmpl, hostname)
        assign_notifier_vars(notifier)
        assign_payload_vars(payload)
        @tmpl = tmpl
        @date = Time.now.utc.rfc2822
        @message_id = Time.now.strftime('%s%9N')
        @hostname = hostname
        assign_head_commit_vars(payload[:head_commit])
      end

      def assign_notifier_vars(notifier)
        @cfg = notifier.cfg
        @from = notifier.fromaddr
        @recipients = notifier.recipients.join(', ')
        @watched_branches = notifier.watched_branches
        @watched_paths = notifier.watched_paths
      end

      def assign_payload_vars(payload)
        @payload = payload
        @repo = "#{payload[:repository][:owner][:name]}/" <<
        "#{payload[:repository][:name]}"
        @ref = payload[:ref]
        @repo_url = payload[:repository][:url]
      end

      def assign_head_commit_vars(hc)
        @head_commit_id = hc[:id]
        @head_commit_url = hc[:url]
        @head_commit_author = hc[:author][:name]
        @head_commit_committer = hc[:committer][:name]
        @head_commit_message_text = hc[:message].to_plaintext
        @head_commit_message_html = hc[:message].to_html
        @head_commit_timestamp = hc[:timestamp]
      end

      def render
        @tmpl.result(binding)
      end
    end
  end
end
