# frozen_string_literal: true

require 'tegimen/delegator'
require 'tegimen/logging'
require 'tegimen/test'

require 'json'
require 'parallel'
require 'time'

module Tegimen
  class TestSuite
    extend Tegimen::Delegator
    extend Tegimen::Logging

    attr_reader :api_key, :definition

    delegate_to proc { Tegimen }, :s3_client, singleton: false

    def initialize(suite, api_key)
      @api_key = api_key

      data = File.read(File.join(suite_folder, "#{suite}.json"))
      @definition = Mash.new(JSON.parse(data))
    end

    # Entry Points
    def start_tests
      start_time = Time.now
      important "Initiating the #{definition.name} test suite at #{start_time}..."

      indent_logs
      definition.experiences.each_pair do |experience, variants|
        definition.locations.each do |location|
          definition.browsers&.each do |browser|
            variants.each do |definition|
              raise "Invalid platform `#{definition.platform}` for experience `#{experience}`." unless [:twitch, :mixer, :youtube, :steam].include?(definition.platform&.to_sym)
              queue_test(experience, location, browser, definition)
            end
          end

          definition.mobile_browsers&.each do |browser|
            variants.each do |definition|
              raise "Invalid platform `#{definition.platform}` for experience `#{experience}`." unless [:twitch, :mixer, :youtube, :steam].include?(definition.platform&.to_sym)
              queue_test(experience, location, 'Chrome', definition, browser)
            end
          end
        end
      end

      Parallel.each(tests, in_processes: Tegimen.parallelize? ? 20 : 0, progress: Tegimen.parallelize?, &:start)
      dedent_logs

      important "Tests started in #{format('%.3f', Time.now - start_time)} seconds. Started #{tests.length} tests as part of this suite."
    end

    def queue_test(experience, location, browser, definition, mobile_browser = nil)
      definition = definition.dup
      definition.update experience: experience, location: location, browser: browser, mobile_browser: mobile_browser
      tests << Test.new(self, definition: definition)
    end

    def check_tests(batch_size: 100)
      start_time = Time.now
      important "Checking in-flight tests for the #{definition.name} test suite at #{start_time}..."
      debug 'Discovering in-flight tests...'
      indent_logs

      s3_client.objects(prefix: state_folder).each do |obj|
        next unless obj.key.end_with?('state.json')

        info "Discovered test state at #{obj.key}"
        tests << obj
        break if tests.length >= batch_size
      end

      Parallel.each(tests, in_processes: Tegimen.parallelize? ? 20 : 0, progress: Tegimen.parallelize?) { |obj| Test.new(self, s3_obj: obj).check }
      dedent_logs

      important "Checking completed in #{format('%.3f', Time.now - start_time)} seconds. Examined the state of #{tests.length} in-flight tests."
    end

    # Helpers

    def dead_letter_folder
      @dead_letter_folder ||= File.join('tegimen-dead-letter', definition.name.sanitize, '/')
    end

    def state_folder
      @state_folder ||= File.join('tegimen-state', definition.name.sanitize, '/')
    end

    def storage_folder
      @storage_folder ||= File.join(definition.name.sanitize, '/')
    end

    def suite_folder
      @suite_folder ||= File.expand_path('../../../suites', __FILE__)
    end

    def tests
      @tests ||= []
    end

  end
end
