class ProxyRule < ActiveRecord::Base

  belongs_to :proxy, touch: true
  belongs_to :metric

  validates :http_method, :pattern, :proxy, :metric_id, presence: true
  validates :delta, numericality: { :only_integer => true, :greater_than => 0 }

  ALLOWED_HTTP_METHODS = %w( GET POST DELETE PUT PATCH HEAD OPTIONS ).freeze
  REGEX_LITERAL   = /[-\w_%,*]+/
  REGEX_VARIABLE  = /\{#{REGEX_LITERAL}\}/
  REGEX_QUERY_STR = /(\?#{REGEX_LITERAL}=(#{REGEX_LITERAL}|#{REGEX_VARIABLE}))?(\&#{REGEX_LITERAL}=(#{REGEX_LITERAL}|#{REGEX_VARIABLE}))*/
  REGEX_PATH      = %r{(/((#{REGEX_LITERAL}|#{REGEX_VARIABLE})(\.#{REGEX_LITERAL})?))+/?}


  validates :pattern, format: { with: /\A(\/|#{REGEX_PATH})\$?(#{REGEX_QUERY_STR})?\Z/x, allow_blank: true }
  # a valid pattern is: slash alone or a path => maybe a dollar sign => maybe a query string

  validates :pattern, length: { maximum: 256 }
  validates :http_method, inclusion: { in: ALLOWED_HTTP_METHODS }
  validate :non_repeated_parameters
  validate :no_vars_in_keys
  validates :redirect_url, :format => URI.regexp(%w(http https)),  allow_blank: true, length: { maximum: 10000 }

  def parameters
    path, *query_string = pattern.to_s.split("?")
    matches = path.scan /\{(.+?)\}/
    if matches.present?
      matches.map(&:first)
    else
      []
    end
  end

  def querystring_parameters
    path, query_string = pattern.to_s.split("?")
    return Hash.new([]) if query_string.blank?
    Hash[query_string.split('&').map{|kv| kv.split('=', 2)}]
  end

  def metric_system_name
    metric.try!(:system_name)
  end

  protected

  def querystring_parameter_keys
    path, query_string = pattern.split("?")
    return [] if query_string.blank?
    query_string.split('&').map{|kv| kv.split('=')}.map(&:first)
  end

  def non_repeated_parameters
    return if pattern.blank?
    if (parameters + querystring_parameter_keys).size != (parameters | querystring_parameter_keys).size
      errors.add(:pattern, "Can't have repeated variable names")
    end
  end

  def no_vars_in_keys
    if querystring_parameters.keys.any?{|k| k =~ /^\{.*\}$/ }
      errors.add(:pattern, "Can't use variables as keys in the querystring")
    end
  end

end
