# frozen_string_literal: true

module GitlabQuality
  module TestTooling
    module Report
      # Uses the API to create GitLab issues for slow tests
      #
      # - Takes the JSON test reports like rspec-*.json`
      # - Takes a project where slow issues should be created
      # - Find issue by title (with test description or test file)
      # - Add test metadata, duration to the issue with group and category labels
      class SlowTestIssue < ReportAsIssue
        include Concerns::FindSetDri
        include Concerns::GroupAndCategoryLabels

        NEW_ISSUE_LABELS = Set.new(['test', 'type::maintenance', 'maintenance::performance', 'priority::3', 'severity::3', 'rspec profiling', 'rspec:slow test']).freeze
        SEARCH_LABELS = %w[test maintenance::performance].freeze

        MultipleIssuesFound = Class.new(StandardError)

        private

        def run!
          puts "Reporting slow tests in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."

          TestResults::Builder.new(files).test_results_per_file do |test_results|
            puts "=> Reporting #{test_results.count} tests in #{test_results.path}"

            test_results.each do |test|
              create_slow_issue(test) if test.slow_test?
            end
          end
        end

        def new_issue_title(test)
          "Slow test in #{super}"
        end

        def new_issue_description(test)
          super +
            <<~DESCRIPTION.chomp
              Slow tests were detected, please see the [test speed best practices guide](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#test-speed)
              to improve them. More context available about this issue in the [top slow tests guide](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#top-slow-tests).

              Add `allowed_to_be_slow: true` to the RSpec test if this is a legit slow test and close the issue.
            DESCRIPTION
        end

        def create_slow_issue(test)
          puts "   => Finding existing issues for slow test '#{test.name}' (run time: #{test.run_time} seconds)..."

          issues = find_issues(test, SEARCH_LABELS, state: 'opened')

          issues.each do |issue|
            puts "   => Existing issue link #{issue['web_url']}"
          end

          create_issue(test) unless issues.any?
        rescue MultipleIssuesFound => e
          warn(e.message)
        end
      end
    end
  end
end