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

require "bundler/setup"
require "optparse"

require_relative "../lib/gitlab_quality/test_tooling"

params = {}
summary_table_opts = {}

messages = []
gitlab_api_token = nil

options = OptionParser.new do |opts|
  opts.banner = "Usage: #{$PROGRAM_NAME} [options]"

  opts.on('-w', '--slack-webhook-url SLACK_WEBHOOK_URL', String, 'Slack webhook URL') do |slack_webhook_url|
    params[:slack_webhook_url] = slack_webhook_url
  end

  opts.on('-a', '--gitlab-api-token TOKEN', String, 'GitLab API token') do |token|
    gitlab_api_token = token unless token.empty?
  end

  opts.on('-c', '--channel CHANNEL', String, 'Slack channel to post the message to') do |channel|
    params[:channel] = channel
  end

  opts.on('-m', '--message MESSAGE', String, 'Post message to Slack') do |message|
    messages << message
  end

  opts.on('-s', '--sort-by SORT', String,
    'Used with the `--include-summary-table` flag — An optional sort for the test summary table. This flag must be positioned before `--include-summary-table`') do |sort_by|
    valid_options = ["Dev Stage", "Total", "Failures", "Errors", "Skipped", "Result"].freeze

    raise ArgumentError, "Invalid sort option: #{sort_by}. Valid options are: #{valid_options.join(', ')}" unless valid_options.include?(sort_by)

    summary_table_opts[:sort_by] = sort_by
  end

  opts.on('-d', '--sort-direction [asc|desc]', String,
    'Used with the `--sort-by` flag — Define the sort direction of the test summary table (default: `asc`)') do |sort_direction|
    raise ArgumentError, "Invalid sort direction: #{sort_direction}. Valid options are: asc, desc" unless %w[asc desc].include?(sort_direction.downcase)

    summary_table_opts[:sort_direction] = sort_direction.downcase.to_sym
  end

  opts.on('-t', '--include-summary-table FILES', String, 'Add a test summary table based on RSpec report files (JUnit XML)') do |files|
    params[:summary_table_files] = files
  end

  opts.on('-j', '--include-failed-jobs-table', 'Add a list of failed jobs in the pipeline') do
    next puts("Failed jobs table requires api token to be set via --gitlab-api-token option, skipping failed jobs table") unless gitlab_api_token

    project_id = ENV['CI_PROJECT_ID']&.to_i || (next puts("CI_PROJECT_ID not set, skipping failed jobs table"))
    pipeline_id = ENV['CI_PIPELINE_ID']&.to_i || (next puts("CI_PIPELINE_ID not set, skipping failed jobs table"))

    jobs = GitlabQuality::TestTooling::GitlabClient::JobsClient.new(token: gitlab_api_token, project: project_id).pipeline_jobs(pipeline_id: pipeline_id, scope: 'failed')
    next if jobs.empty?

    messages << GitlabQuality::TestTooling::FailedJobsTable.create(jobs: jobs)
  rescue StandardError => e
    puts "Failed to fetch failed jobs. #{e.class}: #{e.message}"
  end

  opts.on('-u', '--username USERNAME', String, 'Username to use for the Slack message') do |username|
    params[:username] = username
  end

  opts.on('-i', '--icon-emoji ICON_EMOJI', String, 'Icon emoji to use for the Slack message') do |icon_emoji|
    params[:icon_emoji] = icon_emoji
  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: Post a message to Slack, and optionally add a test summary table based on RSpec report files (JUnit XML)"
    puts opts
    exit
  end

  opts.parse(ARGV)
end

if params.any?
  messages << GitlabQuality::TestTooling::SummaryTable.create(input_files: params.delete(:summary_table_files), **summary_table_opts) if params.key?(:summary_table_files)
  params[:message] = messages.join("\n")

  GitlabQuality::TestTooling::Slack::PostToSlack.new(**params).invoke!
else
  puts options
  exit 1
end