module Support
  class MailClient
    CREDENTIALS = {
      automation_qa: {
        method: ENV["AUTOMATION_EMAIL_METHOD"],
        address: ENV["AUTOMATION_EMAIL_HOST"],
        port: ENV["AUTOMATION_EMAIL_PORT"],
        user_name: ENV["AUTOMATION_EMAIL_USER"],
        password: ENV["AUTOMATION_EMAIL_PASS"],
        enable_ssl: ENV["AUTOMATION_EMAIL_ENABLE_SSL"]
      }
    }.freeze

    def self.automation_qa_client
      @automation_qa_client ||= new(:automation_qa)
    end

    # Public: Wait until a new email has been received within a given timeframe
    # to avoid race conditions between Ruby and mail servers.
    #
    # since - The amount of time since the email may have first been received (in seconds)
    # timeout - The maximum amount of time to wait for the email (in seconds)
    #
    # Example
    #
    # wait_for_new_email(since: 10, timeout: 20)
    #
    # This will check for new email that was received less than 10 seconds before the method was called,
    # and raise an exception if no such email has been found after 20 seconds.
    #
    # Returns true
    def wait_for_new_email(since:, timeout:)
      current_time = Time.now
      # could use a timeout gem, but watir's is good enough
      Watir::Wait.until(timeout: timeout) { @client.last.date.to_time > current_time - since }
    end

    # returns the raw contents of the body of the most recent message received
    def contents_of_last_message
      # no idea why .parts.first is necessary
      sleep 30
      @client.last.parts.first.raw_source
    end

    attr_reader :client

    private

    def initialize(type)
      email_credentials = CREDENTIALS[type]
      @client = case email_credentials.delete(:method).to_sym
                when :pop3
                  Mail::POP3.new(email_credentials)
                when :imap
                  Mail::IMAP.new(email_credentials)
                else
                  fail "unknown email method!"
                end
    end
  end
end
