module CartoDB
  module NamedMapsWrapper
    class Presenter

      NAMED_MAP_TYPE = 'namedmap'
      LAYER_TYPES_TO_DECORATE = [ 'torque' ]
      DEFAULT_TILER_FILTER = 'mapnik'

      # @throws NamedMapsPresenterError
      def initialize(visualization, layergroup, options, configuration)
        @visualization    = visualization
        @options          = options
        @configuration    = configuration
        @layergroup_data  = layergroup
        @named_map_name   = Carto::NamedMaps::Template.new(Carto::Visualization.find(@visualization.id)).name
      end

      # Prepares additional data to decorate layers in the LAYER_TYPES_TO_DECORATE list
      # - Parameters set inside as nil will remove the field itself from the layer data
      # @throws NamedMapsPresenterError
      def get_decoration_for_layer(layer_type, layer_index)
        return {} unless LAYER_TYPES_TO_DECORATE.include? layer_type

        {
          'named_map' =>  {
            'name' =>         @named_map_name,
            'layer_index' =>  layer_index,
            'params' =>       placeholders_data
          },
          'query' => nil  #do not expose SQL query on Torque layers with named maps
        }
      end

      # Prepare a PORO (Hash object) for easy JSONification
      # @see https://github.com/CartoDB/carto.js/blob/privacy-maps/doc/vizjson_format.md
      # @throws NamedMapsPresenterError
      def to_poro
        if @visualization.layers(:cartodb).size == 0
          # When there are no layers don't return named map data
          nil
        else
          api_templates_type = @options.fetch(:https_request, false) ? 'private' : 'public'
          privacy_type = @visualization.password_protected? ? 'private': api_templates_type
          {
            type:     NAMED_MAP_TYPE,
            order:    1,
            options:  {
              type:             NAMED_MAP_TYPE,
              user_name:        @options.fetch(:user_name),
              maps_api_template: ApplicationHelper.maps_api_template(privacy_type),
              sql_api_template: ApplicationHelper.sql_api_template(privacy_type),
              # tiler_* and sql_api_* are kept for backwards compatibility
              tiler_protocol:   @visualization.password_protected? ?
                                  @configuration[:tiler]['private']['protocol'] :
                                  @configuration[:tiler]['public']['protocol'],
              tiler_domain:     @visualization.password_protected? ?
                                  @configuration[:tiler]['private']['domain'] :
                                  @configuration[:tiler]['public']['domain'],
              tiler_port:       @visualization.password_protected? ?
                                  @configuration[:tiler]['private']['port'] :
                                  @configuration[:tiler]['public']['port'],
              filter:           @configuration[:tiler].fetch('filter', DEFAULT_TILER_FILTER),
              named_map:        {
                name:     @named_map_name,
                stat_tag: @visualization.id,
                params:   placeholders_data,
                layers:   configure_layers_data
              },
              attribution: @visualization.attributions_from_derived_visualizations.join(', ')
            }
          }
        end
      end

      private

      def placeholders_data
        data = {}
        @layergroup_data.each { |layer|
          data["layer#{layer[:index].to_s}".to_sym] = layer[:visible] ? 1: 0
        }
        data
      end

      # Extract relevant information from layers
      def configure_layers_data
        # Http/base layers don't appear at viz.json
        layers = @visualization.layers(:cartodb)
        layers_data = Array.new
        layers.each { |layer|
          layer_vizjson = layer.get_presenter(@options, @configuration).to_vizjson_v2
          layers_data.push(data_for_carto_layer(layer_vizjson))
        }
        layers_data
      end

      def data_for_carto_layer(layer_vizjson)
        # TODO: this id will probably be removed from named maps
        data = {
          id: layer_vizjson[:id],
          layer_name: layer_vizjson[:options][:layer_name],
          interactivity: layer_vizjson[:options][:interactivity],
          visible: layer_vizjson[:visible]
        }

        vizjson_infowindow = layer_vizjson[:infowindow]
        vizjson_infowindow_fields = vizjson_infowindow['fields'] if vizjson_infowindow

        if vizjson_infowindow.present? && vizjson_infowindow_fields && !vizjson_infowindow_fields.empty?
          data[:infowindow] = vizjson_infowindow
        end

        vizjson_tooltip = layer_vizjson[:tooltip]
        vizjson_tooltip_fields = vizjson_tooltip['fields'] if vizjson_tooltip

        if vizjson_tooltip.present? && vizjson_tooltip_fields && !vizjson_tooltip_fields.empty?
          data[:tooltip] = vizjson_tooltip
        end

        vizjson_legend = layer_vizjson[:legend]
        data[:legend] = vizjson_legend if vizjson_legend.present? && vizjson_legend.fetch('type') != 'none'

        data
      end
    end
  end
end
