module CartoDB
  module Visualization
    class RedisVizjsonCache

      # This needs to be changed whenever there're changes in the code that require invalidation of old keys
      VERSION = '1'.freeze

      def initialize(redis_cache = $tables_metadata, vizjson_version = 2)
        @redis = redis_cache
        @vizjson_version = vizjson_version
      end

      def cached(visualization_id, https_flag = false, vizjson_version = @vizjson_version)
        key = key(visualization_id, https_flag, vizjson_version)
        value = redis.get(key)
        if value.present?
          JSON.parse(value, symbolize_names: true)
        else
          result = yield
          serialized = JSON.generate(result)
          redis.setex(key, 24.hours.to_i, serialized)
          result
        end
      end

      def invalidate(visualization_id)
        purge_ids([visualization_id])
      end

      def key(visualization_id, https_flag = false, vizjson_version = @vizjson_version, domain = CartoDB.session_domain)
        "visualization:#{visualization_id}:vizjson#{VIZJSON_VERSION_KEY[vizjson_version]}:#{VERSION}:" \
        "#{https_flag ? 'https' : 'http'}:#{domain}"
      end

      def purge(vizs)
        purge_ids(vizs.map(&:id))
      end

      private

      def purge_ids(ids)
        return unless ids.count > 0
        keys = VIZJSON_VERSION_KEY.keys.map { |vizjson_version|
          Cartodb.config.fetch(:vizjson_cache_domains, [CartoDB.session_domain]).map { |domain|
            ids.map { |id| [key(id, false, vizjson_version), key(id, true, vizjson_version, domain)] }.flatten
          }.flatten
        }.flatten
        redis.del keys
      end

      # Needs to know every version because of invalidation
      VIZJSON_VERSION_KEY = {
        2 => '', # VizJSON v2
        3 => '3', # VizJSON v3
        '3n' => '3n', # VizJSON v3 forcing named maps (needed for embeds, see #7093)
        '3a' => '3a' # VizJSON v3 forcing anonymoys maps (needed for editor, see #7150)
      }.freeze

      def redis
        @redis
      end

    end
  end
end
