module Nadir
  class Notification
    def initialize(exception, params = {})
      @exception = exception
      @params = params
    end

    def to_params
      {
        class: @exception.class.name,
        message: @exception.message,
        location: location,
        backtrace: backtrace.join("\n"),
        environment: Nadir.config.env,
        timestamp: Time.current,
        fingerprint: fingerprint,
        host: Socket.gethostname,
        pid: Process.pid,
        request_params: @params.dig(:request, :params),
        request_remote_ip: @params.dig(:request, :remote_ip),
        request_headers: @params.dig(:request, :headers),
        user: @params.dig(:request, :user),
        job: @params.dig(:job),
        revision: revision
      }
    end

    private

    def location
      @params[:location] || $PROGRAM_NAME
    end

    def backtrace
      @_backtrace ||=
        begin
          cleaner = ActiveSupport::BacktraceCleaner.new
          cleaner.remove_filters!
          gem_paths.each { |gem_path| cleaner.add_filter { |line| line.sub(gem_path, '[GEM_ROOT]') } }
          cleaner.add_filter { |line| ruby_path ? line.sub(ruby_path, '[RUBY_ROOT]') : line }
          cleaner.add_filter { |line| line.sub(Nadir.config.root.to_s, '') }
          cleaner.add_filter { |line| line.start_with?('/') ? line.sub('/', '') : line }
          cleaner.add_filter { |line| line.start_with?('.') ? line.sub('.', '') : line  }

          cleaner.clean(@exception.backtrace)
        end
    end

    def fingerprint
      first_backtrace_line = backtrace.find { |trace| trace !~ /pry|irb/ }
      checksum = [first_backtrace_line, @exception.class].join('|')

      Digest::SHA1.hexdigest checksum
    end

    def gem_paths
      @gem_paths ||= Gem.path | [Gem.default_dir]
    end

    def ruby_path
      ENV['RUBY_ROOT'] || `which ruby`.strip.presence
    end

    def revision
      from_git || from_revision_file || from_env
    end

    private

    def from_git
      revision = `git rev-parse HEAD`

      $?.success? ? revision : nil
    end

    def from_revision_file
      revision_file = Nadir.config.root.join('REVISION')

      if File.exist? revision_file
        File.read(revision_file)&.strip
      end
    end

    def from_env
      ENV['COMMIT_HASH']
    end
  end
end