require 'fileutils'
require 'serverspec'
require 'tmpdir'
require 'open3'
require 'pdk/generate/module'
require 'pdk/util/template_uri'
require 'tempfile'
require 'json'

# automatically load any shared examples or contexts
Dir['./spec/acceptance/support/**/*.rb'].sort.each { |f| require f }

if Gem.win_platform?
  set :backend, :cmd
else
  set :backend, :exec
end

# The default directory pdk bin would be installed to on this machine
def default_installed_bin_dir
  if Gem.win_platform?
    # TODO: Also support Windows without cygwin
    '/cygdrive/c/Program\ Files/Puppet\ Labs/DevelopmentKit/bin'
  else
    '/opt/puppetlabs/bin'
  end
end

module Specinfra
  module Backend
    class Cmd
      def execute_script(script)
        if Open3.respond_to?(:capture3)
          stdout, stderr, status = Open3.capture3(script)
          { stdout: stdout, stderr: stderr, status: status }
        else
          stdout = `#{script} 2>&1`
          { stdout: stdout, stderr: nil, status: $? } # rubocop:disable Style/SpecialGlobalVars
        end
      end
    end
  end
end

tempdir = nil
analytics_config = nil

# TODO: --path is deprecated
# bundler won't install bundler into the --path, so in order to access ::Bundler.with_unbundled_env
# from within pdk during spec tests, we have to manually re-add the global gem path :(
bundler_spec = Gem::Specification.find_by_name('bundler')
bundler_path = bundler_spec.gem_dir
ENV['GEM_PATH'] = [ENV['GEM_PATH'], File.absolute_path(File.join(bundler_path, '..', '..')).to_s].compact.join(File::PATH_SEPARATOR)

# Save bundle environment from being purged by specinfra. This needs to be repeated for every example, as specinfra does not correctly reset the environment after a `describe command()` block
# presumably https://github.com/mizzy/specinfra/blob/79b62b37909545b67b7492574a97c300fb1dc91e/lib/specinfra/backend/exec.rb#L143-L165
bundler_env = {}
keys = %w[BUNDLER_EDITOR BUNDLE_BIN_PATH BUNDLE_GEMFILE
          RUBYOPT GEM_HOME GEM_PATH GEM_CACHE]
keys.each do |k|
  bundler_env[k] = ENV[k] if ENV.key? k
end

# dup to avoid pollution from specinfra
Specinfra.configuration.env = bundler_env.dup

RSpec.configure do |c|
  c.before(:suite) do
    RSpec.configuration.template_dir = Dir.mktmpdir
    output, status = Open3.capture2e('git', 'clone', '--bare', PDK::Util::TemplateURI.default_template_uri, RSpec.configuration.template_dir)
    raise "Failed to cache module template: #{output}" unless status.success?

    tempdir = Dir.mktmpdir
    Dir.chdir(tempdir)
    puts "Working in #{tempdir}"

    analytics_config = Tempfile.new('analytics.yml')
    analytics_config.write(YAML.dump('disabled' => true))
    analytics_config.close
    ENV['PDK_ANALYTICS_CONFIG'] = analytics_config.path
  end

  c.after(:suite) do
    Dir.chdir('/')
    FileUtils.rm_rf(tempdir)
    FileUtils.rm_rf(RSpec.configuration.template_dir)
    puts "Cleaned #{tempdir}"
    analytics_config.unlink
  end

  c.after(:each) do |e|
    # Dump stderr into error message to help with debugging if test failed
    if e.exception
      e.exception.message << "\nDumping stderr output:\n\n#{subject.stderr}\n" if subject.stderr != ''
    end

    # recover bundle environment from serverspec munging
    bundler_env.keys.each do |k|
      ENV[k] = bundler_env[k]
    end
  end

  c.expect_with(:rspec) do |e|
    e.include_chain_clauses_in_custom_matcher_descriptions = true
  end
  c.add_setting :fixtures_path, default: File.join(File.dirname(__FILE__), 'fixtures')
  c.add_setting :template_dir
  c.profile_examples = true
end
