require 'history/constants'

module History
  class QueryAudit < History::Base
    attributes :uuid, :action, :user_type, :user_id, :resource_type,
      :resource_id, :description, :created_at, :expiry, :expired_at,
      :changes, :ip, :ip_geo

    def self.audit_types_with_ip_information
      [
        History::AUDIT_SESSION_START_EVENT,
        History::AUDIT_LOGIN_EVENT,
        History::AUDIT_SESSION_INVALIDATE_EVENT
      ]
    end

    def self.resolvable_audit_type?(action:)
      QueryAudit.audit_types_with_ip_information.include?(action)
    end

    def self.hydrate_audits_geo!(audit_collection)
      audit_collection.map do |audit|
        # grab IPs out of the audit description
        #  and use the first item in the array
        ip =
          IpComparison
          .ips_from_text(audit.description)
          .first

        # if we did in fact find an IP, resolve
        #  its geo information
        if ip.present?
          audit.ip_geo =
            IpComparison
            .geo_lookup_ip(ip)
          audit.ip = ip
        end

        # regardless, make sure to put the audit
        #  back, otherwise we'll wind up with a
        #  series of nil objects where audits
        #  once stood.
        audit
      end
    end

    def self.all(options)
      params = History::SearchParams.new(options)
      params = reformat_params(params)

      result = self.client.search(params)

      return paginate([], per_page: params[:per_page], total_pages: 0) if result.audits.nil?

      # wrap the results we've received as QueryAudit for pagination
      audits = result.audits.map { |audit| QueryAudit.from_attributes(audit) }
      paginate audits, per_page: params[:per_page], total_pages: result.total_pages
    end

    # grab a list of audits for actions the user with user_id has taken, and scrub the description field
    # to obtain a list of IP addresses they've used over all time
    def self.ips_for_twitch_user(user_id)
      audits = []

      audit_types_with_ip_information.each do |audit_type|
        results = fetch_all_audits_of_type(user_id, audit_type)
        audits.concat(results) unless results.nil?
      end

      audits.map { |session| session['description'].sub(/IP address: /i, '') }.uniq
    end

    protected

    def self.reformat_params(params)
      params[:created_at_gte] = params[:created_at_gte].to_datetime.utc.round(3).iso8601(3) if params[:created_at_gte].present?
      params[:created_at_lte] = params[:created_at_lte].to_datetime.utc.round(3).iso8601(3) if params[:created_at_lte].present?
      params[:per_page] = PER_PAGE if params[:per_page].blank?

      return params
    end

    private

    def self.fetch_all_audits_of_type(user_id, action_type)
      params = History::SearchParams.new(user_id: user_id, kind: 'twitch_user', action: action_type, per_page: 1000)
      params = reformat_params(params)

      result = self.client.search(params)

      return [] if result.nil?

      total = result.total_pages
      audits = result.audits

      if total && total > 1
        [1..total].each do |i|
          next_page_params = History::SearchParams.new(user_id: user_id, kind: 'twitch_user', action: action_type, page: i, per_page: 1000)
          next_page_params = reformat_params(next_page_params)
          result = self.client.search(next_page_params)
          audits.concat(result.audits) unless result.nil?
        end
      end

      audits
    end
  end
end
