module Gitlab
  module Geo
    class UpdateQueue
      BATCH_SIZE = 250
      NAMESPACE = :geo
      QUEUE = 'updated_projects'

      def initialize
        @redis = redis_connection
      end

      def store(data)
        @redis.rpush(QUEUE, data.to_json) and expire_queue_size!
      end

      def first
        data = fetch(0, 0)
        data.first unless data.empty?
      end

      def last
        data = fetch(-1, -1)
        data.first unless data.empty?
      end

      def fetch_batched_data
        projects = []
        bsize = batch_size

        @redis.multi do
          projects = @redis.lrange(QUEUE, 0, bsize-1)
          @redis.ltrim(QUEUE, bsize, -1)
        end

        expire_queue_size!
        deserialize(projects.value)
      end

      def store_batched_data(projects)
        @redis.pipelined do
          projects.reverse_each do |project|
            # enqueue again to the head of the queue
            @redis.lpush(QUEUE, project.to_json)
          end
        end
        expire_queue_size!
      end

      def batch_size
        queue_size > BATCH_SIZE ? BATCH_SIZE : queue_size
      end

      def queue_size
        @queue_size ||= fetch_queue_size
      end

      def empty?
        queue_size == 0
      end

      def empty!
        @redis.del(QUEUE)
      end

      protected

      def fetch(start, stop)
        deserialize(@redis.lrange(QUEUE, start, stop))
      end

      def fetch_queue_size
        @redis.llen(QUEUE)
      end

      def expire_queue_size!
        @queue_size = nil
      end

      def deserialize(data)
        data.map! { |item| JSON.parse(item) } unless data.empty?
        data
      end

      def redis_connection
        redis_config_file = Rails.root.join('config', 'resque.yml')

        redis_url_string = if File.exists?(redis_config_file)
                             YAML.load_file(redis_config_file)[Rails.env]
                           else
                             'redis://localhost:6379'
                           end

        Redis::Namespace.new(NAMESPACE, redis: Redis.new(url: redis_url_string))
      end
    end
  end
end