require 'debci/job'

module Debci
  module TestHandler
    def enqueue(job, priority = 5)
      job.enqueue(priority)
    end

    def valid_package_name?(pkg)
      pkg =~ /^[a-z0-9][a-z0-9+.-]+$/
    end

    def validate_priority(priority)
      priority.between?(1, 10)
    end

    def request_batch_tests(test_requests, requestor, priority = 5)
      test_requests.each do |request|
        request['arch'].each do |arch|
          request_tests(request['tests'], request['suite'], arch, requestor, priority)
        end
      end
    end

    def validate_batch_test(test_requests)
      errors = []
      errors.push("Not an array") unless test_requests.is_a?(Array)
      test_requests.each_with_index do |request, index|
        request_suite = request['suite']
        errors.push("No suite at request index #{index}") if request_suite == ''
        errors.push("Wrong suite (#{request_suite}) at request index #{index}, available suites: #{Debci.config.suite_list.join(', ')}") unless Debci.config.suite_list.include?(request_suite)
        archs = Array(request['arch']).reject(&:empty?)
        errors.push("No archs are specified at request index #{index}") if archs.empty?
        errors.push("Wrong archs (#{archs.join(', ')}) at request index #{index}, available archs: #{Debci.config.arch_list.join(', ')}") if (Debci.config.arch_list & archs).length != archs.length
        request['tests'].each_with_index do |t, i|
          errors.push("Invalid package name at request index #{index} and test index #{i}") unless valid_package_name?(t['package'])
          errors.push("Invalid value for bool parameter is_private at request index #{index} and test index #{i}") unless t['is_private'].in? [true, false, nil]
          errors.push("Invalid extra apt sources at request index #{index} and test index #{i}") unless invalid_extra_apt_sources(t['extra-apt-sources']).empty?
          backend = t['backend']
          if !backend.blank? && !Debci.config.backend_list.include?(backend)
            errors.push("Invalid backend: #{backend}")
          end
          autopkgtest = t['autopkgtest']
          if !autopkgtest.blank? && !Debci.config.autopkgtest_variants.keys.include?(autopkgtest)
            errors.push("Invalid autopkgtest: #{autopkgtest}")
          end
        end
      end
      errors
    end

    def validate_tests(tests)
      errors = []
      tests.each do |test|
        errors << "Invalid package name: #{test['package']}" unless valid_package_name?(test['package'])
        errors << "Invalid value for bool parameter is_private for package: #{test['package']}" unless test['is_private'].in? [true, false, nil]
        apt_sources_errors = invalid_extra_apt_sources(test['extra-apt-sources'])
        errors << "Invalid value for extra_apt_sources: #{apt_sources_errors}" unless apt_sources_errors.empty?
        backend = test['backend']
        if !backend.blank? && !Debci.config.backend_list.include?(backend)
          errors << "Invalid backend: #{backend}"
        end
        autopkgtest = test['autopkgtest']
        if !autopkgtest.blank? && !Debci.config.autopkgtest_variants.keys.include?(autopkgtest)
          errors << "Invalid autopkgtest: #{autopkgtest}"
        end
      end
      errors
    end

    def request_tests(tests, suite, arch, requestor, priority = 5)
      jobs = []
      tests.each do |test|
        pkg = test['package']
        enqueue = true
        status = nil
        date = nil
        if Debci.reject_list.include?(pkg, suite: suite, arch: arch) || !valid_package_name?(pkg)
          next
        end

        backend = test['backend']
        backend = nil if backend.blank?

        autopkgtest = test['autopkgtest']
        autopkgtest = nil if autopkgtest.blank?

        package = Debci::Package.find_or_create_by!(name: test['package'])
        job = Debci::Job.create!(
          package: package,
          suite: suite,
          arch: arch,
          requestor: requestor,
          status: status,
          date: date,
          requested_backend: backend,
          autopkgtest: autopkgtest,
          trigger: test['trigger'],
          pin_packages: test['pin-packages'],
          is_private: test['is_private'] || false,
          extra_apt_sources: test['extra-apt-sources']
        )
        jobs << job if enqueue
      end
      jobs.each do |job|
        self.enqueue(job, priority)
      end
    end

    def get_job_to_retry(run_id)
      begin
        job = Debci::Job.find(run_id)
      rescue ActiveRecord::RecordNotFound
        halt(400, "Job ID not known: #{run_id}")
      end
      halt(403, "Package #{job.package.name} is in the REJECT list and cannot be retried") if Debci.reject_list.include?(job.package, suite: job.suite, arch: job.arch)
      job
    end
  end
end
