require_relative 'build/check'
require_relative 'build/info/secrets'
require_relative 'ohai_helper'
require_relative 'util'

require 'gitlab'

class PackageSizeCheck
  CE_MAX_SIZE_MB = Gitlab::Util.get_env('CE_MAX_SIZE_MB')&.to_i || 950
  EE_MAX_SIZE_MB = Gitlab::Util.get_env('EE_MAX_SIZE_MB')&.to_i || 1000
  ALERT_ENDPOINT = Gitlab::Util.get_env('PACKAGE_SIZE_ALERT_ENDPOINT')
  ALERT_TOKEN = Gitlab::Util.get_env('PACKAGE_SIZE_ALERT_TOKEN')

  class << self
    def fetch_sizefile
      sizefile_url = URI("#{Build::Info::CI.package_download_url}.size")

      # We have to use net/http here because `gitlab` gem's `download_job_artifact_file`
      # method doesn't support plain text files. It has to be either binary or valid JSON.
      # https://github.com/NARKOZ/gitlab/issues/621
      req = Net::HTTP::Get.new(sizefile_url)
      req['PRIVATE-TOKEN'] = Build::Info::Secrets.api_token
      res = Net::HTTP.start(sizefile_url.hostname, sizefile_url.port, use_ssl: true) do |http|
        http.request(req)
      end

      size = res.body

      FileUtils.mkdir_p('pkg/ubuntu-jammy')
      File.write('pkg/ubuntu-jammy/gitlab.deb.size', size)
    end

    def generate_sizefiles(files)
      files.each do |file|
        File.write("#{file}.size", File.stat(file).size)
      end
    end

    def check_and_alert(package_sizefile = 'pkg/ubuntu-jammy/gitlab.deb.size')
      permitted_size = if Build::Check.is_ee?
                         EE_MAX_SIZE_MB
                       else
                         CE_MAX_SIZE_MB
                       end

      package_size = File.read(package_sizefile).strip.to_i / 1024.0**2
      success = package_size <= permitted_size

      return if success

      puts "Package size #{package_size.round(2)}MB above threshold of #{permitted_size}MB."
      alert(package_size, permitted_size)
      exit 1
    end

    def alert(package_size, permitted_size)
      unless ALERT_ENDPOINT && ALERT_TOKEN
        puts 'Alert endpoint and token not defined. Not triggering an alert.'
        return
      end

      uri = URI(ALERT_ENDPOINT)
      result = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
        request = Net::HTTP::Post.new(uri)
        request['Content-Type'] = 'application/json'
        request['Authorization'] = "Bearer #{ALERT_TOKEN}"
        request.body = payload(package_size, permitted_size).to_json
        http.request(request)
      end

      return if result.code == '200'

      puts 'Failed to trigger alert.'
      puts "Response code: #{result.code}"
      puts "Response message: #{result.message}"
      exit 1
    end

    def payload(package_size, permitted_size)
      # In omnibus-gitlab canonical mirror alert settings, we have mapped these
      # custom fields to GitLab alert fields as follows:
      # title => title
      # description => description
      # pipeline => monitoring_tool
      # os => host
      # fingerprint => fingerprint
      #
      # Also, we are setting a custom static value for fingerprint so that
      # alerts will be grouped together.
      {
        title: "#{Build::Info::Package.edition.upcase} package size exceeded threshold of #{permitted_size} MB",
        description: "Package size: #{package_size.round(2)} MB.",
        pipeline: Gitlab::Util.get_env('CI_PIPELINE_URL'),
        os: OhaiHelper.platform_dir,
        fingerprint: "omnibus-gitlab-package-size-#{Build::Info::Package.edition}" # For automatic grouping of alerts
      }
    end
  end
end
