# frozen_string_literal: true

module Indicina
  class Index
    attr_reader :suite, :platform, :experience, :location, :browser, :mobile_browser, :effective_browser

    def initialize(suite, platform, experience, date_range:, location: nil, browser: nil, mobile_browser: nil)
      @suite = suite
      @platform = platform
      @experience = experience
      @location = location
      @browser = browser
      @mobile_browser = mobile_browser
      @effective_browser = mobile_browser || browser
      @date_range = date_range

      @tests = suite.tests_dataset.where(platform: platform, experience: experience, tested_at: date_range, valid: true)
      @tests = @tests.where(location: location) unless location.nil?
      @tests = @tests.where(browser: browser) unless browser.nil?
      @tests = @tests.where(mobile_browser: mobile_browser) unless mobile_browser.nil?
    end

    def locations
      raise "Shouldn't be called unless @location is nil." unless location.nil?
      @locations ||= suite.locations.map do |location|
        Index.new(suite, platform, experience, date_range: @date_range, location: location, browser: browser, mobile_browser: mobile_browser)
      end
    end

    def best_run
      @best_run ||= eligible_runs.all.sort_by { |run| (run.load_time - true_median).abs }.first
    end

    def samples
      runs.count
    end

    def true_median
      return 0 if load_times.count.zero?

      half_count = load_times.count / 2 - 1
      load_times.count.odd? ? load_times[half_count + 1] : (load_times[half_count] + load_times[half_count + 1]) / 2
    end

    def url
      @tests.select(:url).first.url
    end

    private

    def runs
      @runs ||= TestRun.with_tests(@tests)
    end

    def eligible_runs
      @eligible_runs ||= runs.where(is_median: true)
    end

    def load_times
      @load_times ||= runs.select(:load_time).map(&:load_time).sort
    end
  end
end
