require_dependency 'csv'

module ThreeScale
  module Rake
    class GannettImporter

      attr_reader :data, :headings, :gannett, :rules

      def self.run!
      end

      def initialize(path, gannett_id)
        @gannett = Account.providers.find(gannett_id)
        @data = CSV.read(path)
        @headings = data.shift

        @rules = []
      end

      def import
        data.each do |rule|
          f = -> (elem) { fetch(rule, elem) }
          service_id = f.(:service_id).to_i
          system_name = f.('3scale method')
          metric = gannett.metrics.where(system_name: system_name).first!

          extra_query_params = f.("Extra query parameters").presence ? '?'+f.("Extra query parameters") : ''

          redirect_url = 'http://' + f.('Target Hostname at Origin') + f.('Target Path at Origin') + extra_query_params
          proxy = gannett.services.find(service_id).proxy
          imported_rule = proxy.proxy_rules.new(pattern: f.('Request Path'), http_method: f.('http method'), delta:1 , metric_id: metric.id , metric_system_name: system_name , redirect_url: redirect_url)
          @rules << imported_rule
        end
      end

      def check_services
        rules_services = Set.new(data.map{|rule| rule[index_of('service_id')].to_i })
        gannett_services = Set.new(gannett.services.map(&:id))

        nonexisting_services = (rules_services - gannett_services)
        nonexisting_services.empty?
      end

      def valid?
        check_services and rules.all?(&:valid?)
      end

      def proxy_endpoint_set(service_id, public_endpoint, user_key_name)
        proxy = @gannett.services.find(service_id).proxy
        proxy.update_attribute(:endpoint, public_endpoint)
        proxy.update_attribute(:auth_user_key, user_key_name)
      end

      def save_all_rules
        delete_default_rules
        services = data.map do |rule|
          f = -> (elem) { fetch(rule, elem) }
          service_id = f.(:service_id).to_i
          [service_id , fetch(rule, 'Request Hostname'), fetch(rule, 'Key Authentication')]
        end.uniq(&:first)

        services.each {|(service_id, endpoint, user_key_name)| proxy_endpoint_set(service_id, endpoint, user_key_name) }

        ok, nok = rules.partition{|x| x.save }
      end

      def delete_default_rules
        proxies = rules.map(&:proxy).uniq

        proxies.each do |p|
          p.proxy_rules.where(pattern: '/').destroy_all
        end
      end

      def fetch(rule, field)
        rule[index_of(field.to_s)].to_s
      end

      def index_of(heading)
        headings.find_index(heading) or 10000000
      end

    end
  end
end
