#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"
require "optparse"

require_relative "../lib/gitlab_quality/test_tooling"

params = {}

options = OptionParser.new do |opts|
  def to_boolean(value, default)
    return default if value.nil?
    return true if value == true || value.to_s.casecmp('true').zero?

    false
  end

  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"

  opts.on('-i', '--input-files INPUT_FILES', String, 'RSpec report files (JSON or JUnit XML) [REQUIRED]') do |input_files|
    params[:input_files] = input_files
  end

  opts.on('-p', '--project PROJECT', String, 'Can be an integer or a group/project string [REQUIRED]') do |project|
    params[:project] = project
  end

  opts.on('-t', '--token TOKEN', String, 'A valid access token with `api` scope and Maintainer permission in PROJECT [REQUIRED]') do |token|
    params[:token] = token
  end

  opts.on('--enable-issue-update [BOOLEAN]', "Enable/disable test health issue creation/update (default: true)") do |toggle|
    params[:issue_update_enabled] = to_boolean(toggle, true)
  end

  # Google Cloud Storage (GCS) options
  opts.on('--enable-gcs [BOOLEAN]', "Enable/disable the push of JSON data to a Google Cloud Storage (GCS) bucket (default: false)") do |toggle|
    params[:gcs_enabled] = to_boolean(toggle, false)
  end

  opts.on('--gcs-project-id GCS_PROJECT_ID', String, 'Google Cloud project ID for GCS bucket access') do |project_id|
    params[:gcs_project_id] = project_id
  end

  opts.on('--gcs-bucket GCS_BUCKET', String, 'Name of the GCS bucket to store metrics data') do |bucket|
    params[:gcs_bucket] = bucket
  end

  opts.on('--gcs-credentials GCS_CREDENTIALS', String, 'GCS service account credentials (file path or string)') do |credentials|
    params[:gcs_credentials] = credentials
  end

  opts.on('--max-diff-ratio MAX_DIFF_RATO', Float, 'Max stacktrace diff ratio for failure issues detection') do |max_diff_ratio|
    params[:max_diff_ratio] = max_diff_ratio
  end

  opts.on('-r', '--related-issues-file RELATED_ISSUES_FILE', String, 'The file path for the related issues') do |related_issues_file|
    params[:related_issues_file] = related_issues_file
  end

  opts.on('--base-issue-labels BASE_ISSUE_LABELS', String,
    'Labels to add to new failure issues') do |base_issue_labels|
    params[:base_issue_labels] = base_issue_labels.split(',')
  end

  opts.on('--exclude-labels-for-search EXCLUDE_LABELS_FOR_SEARCH', String,
    'Labels to exclude when searching for existing issues') do |exclude_labels_for_search|
    params[:exclude_labels_for_search] = exclude_labels_for_search.split(',')
  end

  opts.on('--dry-run', "Perform a dry-run (don't create or update issues)") do
    params[:dry_run] = true
  end

  opts.on_tail('-v', '--version', 'Show the version') do
    require_relative "../lib/gitlab_quality/test_tooling/version"
    puts "#{$PROGRAM_NAME} : #{GitlabQuality::TestTooling::VERSION}"
    exit
  end

  opts.on_tail('-h', '--help', 'Show the usage') do
    puts "Purpose: Relate test failures to failure issues from RSpec report files (JSON or JUnit XML)"
    puts opts
    exit
  end
end

begin
  options.parse!(ARGV)

  required_options = [:input_files, :project, :token]
  missing_options = required_options.select { |option| params[option].nil? }

  if params[:gcs_enabled]
    gcs_required_options = [:gcs_project_id, :gcs_bucket, :gcs_credentials]
    missing_gcs_options = gcs_required_options.select { |option| params[option].nil? }

    missing_options.concat(missing_gcs_options) if missing_gcs_options.any?
  end

  if missing_options.any?
    warn "Error: Missing required options: #{missing_options.map { |o| "--#{o.to_s.tr('_', '-')}" }.join(', ')}\n"
    warn options
    exit 1
  end

  GitlabQuality::TestTooling::Report::FailedTestIssue.new(**params).invoke!
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
  warn "Error: #{e.message}"
  warn options
  exit 1
end
