require 'pdk'

module PDK
  module Util
    class VendoredFile
      class DownloadError < StandardError; end

      attr_reader :file_name, :url

      def initialize(file_name, url)
        @file_name = file_name
        @url = url
      end

      def read
        require 'pdk/util'
        require 'pdk/util/filesystem'

        return PDK::Util::Filesystem.read_file(package_vendored_path) if PDK::Util.package_install?
        return PDK::Util::Filesystem.read_file(gem_vendored_path) if PDK::Util::Filesystem.file?(gem_vendored_path)

        content = download_file

        # TODO: should only write if it's valid JSON
        # TODO: need a way to invalidate if out of date
        PDK::Util::Filesystem.mkdir_p(File.dirname(gem_vendored_path))
        PDK::Util::Filesystem.write_file(gem_vendored_path, content)
        content
      end

      private

      def download_file
        require 'uri'
        require 'net/https'
        require 'openssl'

        http_errors = [
          EOFError,
          Errno::ECONNRESET,
          Errno::EINVAL,
          Errno::ECONNREFUSED,
          Net::HTTPBadResponse,
          Net::HTTPHeaderSyntaxError,
          Net::ProtocolError,
          Timeout::Error
        ]

        PDK.logger.debug format('%{file_name} was not found in the cache, downloading it from %{url}.', file_name: file_name, url: url)

        uri = URI.parse(url)
        http = Net::HTTP.new(uri.host, uri.port)
        http.use_ssl = true
        if Gem.win_platform?
          http.ca_file = 'C:/Program Files/Puppet Labs/DevelopmentKit/ssl/cert.pem'
          http.verify_mode = OpenSSL::SSL::VERIFY_PEER
        end
        request = Net::HTTP::Get.new(uri.request_uri)
        response = http.request(request)

        raise DownloadError, format('Unable to download %{url}. %{code}: %{message}.', url: url, code: response.code, message: response.message) unless response.code == '200'

        response.body
      rescue *http_errors => e
        raise DownloadError, format('Unable to download %{url}. Check internet connectivity and try again. %{error}', url: url, error: e)
      end

      def package_vendored_path
        require 'pdk/util'

        @package_vendored_path ||= File.join(PDK::Util.package_cachedir, file_name)
      end

      def gem_vendored_path
        require 'pdk/util'
        require 'pdk/version'

        @gem_vendored_path ||= File.join(PDK::Util.cachedir, PDK::VERSION, file_name)
      end
    end
  end
end
