# frozen_string_literal: true

module PlausibleApi
  module Stats
    class Base < ApiBase
      ALLOWED_PERIODS = %w[12mo 6mo month 30d 7d day custom]
      ALLOWED_METRICS = %w[visitors visits pageviews views_per_visit bounce_rate visit_duration events]
      ALLOWED_COMPARE = %w[previous_period]
      ALLOWED_INTERVALS = %w[date month]
      ALLOWED_PROPERTIES = %w[event:goal event:page visit:entry_page visit:exit_page visit:source
        visit:referrer visit:utm_medium visit:utm_source visit:utm_campaign
        visit:utm_content visit:utm_term visit:device visit:browser
        visit:browser_version visit:os visit:os_version visit:country visit:region visit:city
        event:props:.+]
      ALLOWED_FILTER_OPERATORS = %w[== != \|]

      def initialize(options = {})
        @options = {compare: nil, date: nil, filters: nil, interval: nil,
                    limit: nil, metrics: nil, page: nil, period: nil,
                    property: nil}.merge(options)
        @options[:period] = "custom" if @options[:date]
      end

      def request_class
        Net::HTTP::Get
      end

      def request_path
        params = @options.select { |_, v| !v.to_s.empty? }
        [request_path_base, URI.encode_www_form(params)].reject { |e| e.empty? }.join("&")
      end

      def parse_response(body)
        JSON.parse(body)["results"]
      end

      def errors
        e = "Not a valid parameter. Allowed parameters are: "

        errors = []
        if @options[:period]
          errors.push({period: "#{e}#{ALLOWED_PERIODS.join(", ")}"}) unless ALLOWED_PERIODS.include? @options[:period]
        end
        if @options[:metrics]
          metrics_array = @options[:metrics].split(",")
          errors.push({metrics: "#{e}#{ALLOWED_METRICS.join(", ")}"}) unless metrics_array & ALLOWED_METRICS == metrics_array
        end
        if @options[:compare]
          errors.push({compare: "#{e}#{ALLOWED_COMPARE.join(", ")}"}) unless ALLOWED_COMPARE.include? @options[:compare]
        end
        if @options[:interval]
          errors.push({interval: "#{e}#{ALLOWED_INTERVALS.join(", ")}"}) unless ALLOWED_INTERVALS.include? @options[:interval]
        end
        if @options[:property]
          unless @options[:property].match?(/^(#{ALLOWED_PROPERTIES.join('|')})$/)
            errors.push({property: "#{e}#{ALLOWED_PROPERTIES.join(", ")}"}) unless ALLOWED_PROPERTIES.include? @options[:property]
          end
        end
        @options[:filters]&.split(";")&.each do |filter|
          unless filter.match?(/^(#{ALLOWED_PROPERTIES.join('|')})(#{ALLOWED_FILTER_OPERATORS.join('|')})(.+)$/)
            errors.push({filters: "Filter #{filter} is not valid"})
          end
        end

        if @options[:limit]
          errors.push({limit: "Limit param must be a positive number"}) unless @options[:limit].to_i > 0
        end
        if @options[:page]
          errors.push({page: "Page param must be a positive number"}) unless @options[:page].to_i > 0
        end
        if @options[:date]
          errors.push({date: "You must define the period parameter as custom"}) unless @options[:period] == "custom"
          date_array = @options[:date].split(",")
          errors.push({date: "You must define start and end dates divided by comma"}) unless date_array.length == 2
          regex = /\d{4}-\d{2}-\d{2}/
          errors.push({date: "Wrong format for the start date"}) unless date_array[0]&.match?(regex)
          errors.push({date: "Wrong format for the end date"}) unless date_array[1]&.match?(regex)
        end
        errors
      end
    end
  end
end