class Compliance::ComplianceCLI

def self.banner(command, _namespace = nil, _subcommand = false)

TODO: find another solution, once https://github.com/erikhuda/thor/issues/261 is fixed
def self.banner(command, _namespace = nil, _subcommand = false)
  "#{basename} #{subcommand_prefix} #{command.usage}"
end

def self.subcommand_prefix

def self.subcommand_prefix
  namespace
end

def download(profile_name)

def download(profile_name)
  o = options.dup
  configure_logger(o)
  config = Compliance::Configuration.new
  return if !loggedin(config)
  profile_name = Compliance::API.sanitize_profile_name(profile_name)
  if Compliance::API.exist?(config, profile_name)
    puts "Downloading `#{profile_name}`"
    fetcher = Compliance::Fetcher.resolve(
      {
        compliance: profile_name,
      },
    )
    # we provide a name, the fetcher adds the extension
    _owner, id = profile_name.split('/')
    file_name = fetcher.fetch(o.name || id)
    puts "Profile stored to #{file_name}"
  else
    puts "Profile #{profile_name} is not available in Chef Compliance."
    exit 1
  end
end

def exec(*tests)

def exec(*tests)
  config = Compliance::Configuration.new
  return if !loggedin(config)
  o = opts(:exec).dup
  diagnose(o)
  configure_logger(o)
  # iterate over tests and add compliance scheme
  tests = tests.map { |t| 'compliance://' + Compliance::API.sanitize_profile_name(t) }
  runner = Inspec::Runner.new(o)
  tests.each { |target| runner.add_target(target) }
  exit runner.run
rescue ArgumentError, RuntimeError, Train::UserError => e
  $stderr.puts e.message
  exit 1
end

def loggedin(config)

def loggedin(config)
  serverknown = !config['server'].nil?
  puts 'You need to login first with `inspec compliance login`' if !serverknown
  serverknown
end

def login(server)

def login(server)
  options['server'] = server
  Compliance::API.login(options)
  config = Compliance::Configuration.new
  puts "Stored configuration for Chef #{config['server_type'].capitalize}: #{config['server']}' with user: '#{config['user']}'"
end

def logout

def logout
  config = Compliance::Configuration.new
  unless config.supported?(:oidc) || config['token'].nil? || config['server_type'] == 'automate'
    config = Compliance::Configuration.new
    url = "#{config['server']}/logout"
    Compliance::HTTP.post(url, config['token'], config['insecure'], !config.supported?(:oidc))
  end
  success = config.destroy
  if success
    puts 'Successfully logged out'
  else
    puts 'Could not log out'
  end
end

def profiles

def profiles
  config = Compliance::Configuration.new
  return if !loggedin(config)
  # set owner to config
  config['owner'] = options['owner'] || config['user']
  msg, profiles = Compliance::API.profiles(config)
  profiles.sort_by! { |hsh| hsh['title'] }
  if !profiles.empty?
    # iterate over profiles
    headline('Available profiles:')
    profiles.each { |profile|
      owner = profile['owner_id'] || profile['owner']
      li("#{profile['title']} v#{profile['version']} (#{mark_text(owner + '/' + profile['name'])})")
    }
  else
    puts msg, 'Could not find any profiles'
    exit 1
  end
rescue Compliance::ServerConfigurationMissing
  STDERR.puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
  exit 1
end

def upload(path) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, PerceivedComplexity, Metrics/CyclomaticComplexity

rubocop:disable Metrics/MethodLength, Metrics/AbcSize, PerceivedComplexity, Metrics/CyclomaticComplexity
def upload(path) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, PerceivedComplexity, Metrics/CyclomaticComplexity
  config = Compliance::Configuration.new
  return if !loggedin(config)
  # set owner to config
  config['owner'] = options['owner'] || config['user']
  unless File.exist?(path)
    puts "Directory #{path} does not exist."
    exit 1
  end
  vendor_deps(path, options) if File.directory?(path)
  o = options.dup
  configure_logger(o)
  # check the profile, we only allow to upload valid profiles
  profile = Inspec::Profile.for_target(path, o)
  # start verification process
  error_count = 0
  error = lambda { |msg|
    error_count += 1
    puts msg
  }
  result = profile.check
  unless result[:summary][:valid]
    error.call('Profile check failed. Please fix the profile before upload.')
  else
    puts('Profile is valid')
  end
  # determine user information
  if (config['token'].nil? && config['refresh_token'].nil?) || config['user'].nil?
    error.call('Please login via `inspec compliance login`')
  end
  # read profile name from inspec.yml
  profile_name = profile.params[:name]
  # read profile version from inspec.yml
  profile_version = profile.params[:version]
  # check that the profile is not uploaded already,
  # confirm upload to the user (overwrite with --force)
  if Compliance::API.exist?(config, "#{config['owner']}/#{profile_name}##{profile_version}") && !options['overwrite']
    error.call('Profile exists on the server, use --overwrite')
  end
  # abort if we found an error
  if error_count > 0
    puts "Found #{error_count} error(s)"
    exit 1
  end
  # if it is a directory, tar it to tmp directory
  if File.directory?(path)
    archive_path = Dir::Tmpname.create([profile_name, '.tar.gz']) {}
    puts "Generate temporary profile archive at #{archive_path}"
    profile.archive({ output: archive_path, ignore_errors: false, overwrite: true })
  else
    archive_path = path
  end
  puts "Start upload to #{config['owner']}/#{profile_name}"
  pname = ERB::Util.url_encode(profile_name)
  if Compliance::API.is_automate_server?(config) || Compliance::API.is_automate2_server?(config)
    puts 'Uploading to Chef Automate'
  else
    puts 'Uploading to Chef Compliance'
  end
  success, msg = Compliance::API.upload(config, config['owner'], pname, archive_path)
  if success
    puts 'Successfully uploaded profile'
  else
    puts 'Error during profile upload:'
    puts msg
    exit 1
  end
end

def version

def version
  config = Compliance::Configuration.new
  info = Compliance::API.version(config)
  if !info.nil? && info['version']
    puts "Name:    #{info['api']}"
    puts "Version: #{info['version']}"
  else
    puts 'Could not determine server version.'
    exit 1
  end
rescue Compliance::ServerConfigurationMissing
  puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
  exit 1
end