require 'http'
require 'json'

require_relative 'build/info/docker'
require_relative 'util'

PipelineTriggerFailure = Class.new(StandardError)
class DeployerHelper
  TRIGGER_RETRY_INTERVAL = 5
  TRIGGER_RETRIES = 3
  def initialize(trigger_token, deploy_env, trigger_ref)
    @deploy_env = deploy_env
    @trigger_token = trigger_token
    @trigger_ref = trigger_ref
    @endpoint = "https://#{trigger_host}/api/v4"
  end

  def trigger_deploy
    begin
      retries ||= 0
      resp = HTTP.post(pipeline_trigger_url, form: form_data_for_trigger)
      puts "Triggering pipeline #{pipeline_trigger_url} for ref #{@trigger_ref}, status code: #{resp.status}"
      raise PipelineTriggerFailure unless resp.status == 201
    rescue PipelineTriggerFailure
      if (retries += 1) < TRIGGER_RETRIES
        sleep TRIGGER_RETRY_INTERVAL
        puts "Retrying pipeline trigger ##{retries} due to invalid status: #{resp.status}"
        retry
      end
      raise "Unable to trigger pipeline after #{retries} retries"
    end
    web_url_from_trigger(resp)
  end

  def web_url_from_trigger(resp)
    JSON.parse(resp.body.to_s)['web_url']
  rescue JSON::ParserError
    raise "Unable to parse response from pipeline trigger, got #{resp.body}"
  end

  def pipeline_trigger_url
    "#{@endpoint}/projects/#{trigger_project}/trigger/pipeline"
  end

  def trigger_host
    @trigger_host ||= Gitlab::Util.get_env('DEPLOYER_TRIGGER_HOST') || 'ops.gitlab.net'
  end

  def trigger_project
    # Project ID 135 is the project ID of deployer on ops.gitlab.net
    @trigger_project ||= Gitlab::Util.get_env('DEPLOYER_TRIGGER_PROJECT') || '135'
  end

  def release
    @release ||= Build::Info::Docker.tag
  end

  def form_data_for_trigger
    {
      'token' => @trigger_token,
      'ref' => @trigger_ref,
    }.merge(deployer_env_vars.map { |k, v| ["variables[#{k}]", v] }.to_h)
  end

  def deployer_env_vars
    {
      'DEPLOY_ENVIRONMENT' => @deploy_env,
      'DEPLOY_VERSION' => Gitlab::Util.get_env('DEPLOYER_VERSION') || release,
      'DEPLOY_USER' => Gitlab::Util.get_env('DEPLOYER_DEPLOY_USER') || 'deployer'
    }
  end
end
