# frozen_string_literal: true

module ReleaseTools
  module Promotion
    class Manager
      include ::SemanticLogger::Loggable

      class UnsafeProductionError < StandardError; end

      def status
        @status ||= ProductionStatus.new(:active_gprd_deployments)
      end

      # Authorize production promotion based on the current system status
      #
      # @param package_version [String] the package we want to promote
      # @param issue [ReleaseTools::Issue] the issue to track the outcome
      # @raise [UnsafeProductionError] if the deployment isn't authorized
      def authorize!(package_version, issue)
        Retriable.with_context(:api) do
          create_issue_comment(issue, package_version)
        end

        raise UnsafeProductionError unless safe?
      end

      private

      def safe?
        ignore_production_checks? || status.fine?
      end

      # ignore_production_checks return the reason for bypassing production checks
      #
      # Production check bypassing starts with a chatops command.
      # If the release manager provides a reason for bypassing the checks,
      # it will be propagated to the deployer, and then to release-tools using
      # the IGNORE_PRODUCTION_CHECKS trigger variable.
      # On every stage this defaults to 'false', meaning that checks should not
      # be ignored.
      #
      # @return [String] the reason for bypassing the production checks, defaults to 'false'
      def ignore_production_checks
        CGI.unescape(ENV.fetch('IGNORE_PRODUCTION_CHECKS', 'false'))
      end

      # ignore_production_checks? verifies if a reason for bypassing production checks was provided
      #
      # @see Manager#ignore_production_checks
      def ignore_production_checks?
        ignore_production_checks != 'false'
      end

      def note(package_version)
        StatusNote.new(
          status: status,
          package_version: package_version,
          override_reason: ignore_production_checks
        )
      end

      def create_issue_comment(issue, package_version)
        if SharedStatus.dry_run?
          logger.warn(
            'Dry run mode, no comment will be posted',
            issue: issue.url,
            package_version: package_version,
            production_healthy: status.fine?,
            ignore_production_checks: ignore_production_checks
          )

          return
        end

        GitlabClient.create_issue_note(
          issue.project,
          issue: issue,
          body: note(package_version).body
        )
      end
    end
  end
end
