# frozen_string_literal: true

module ReleaseTools
  module Metrics
    # This class is used to set the auto_deploy_building_package_state metric, which tracks packages that are newer than
    # what is already present on gstg-cny.
    class AutoDeployBuildingPackageState
      include ::SemanticLogger::Loggable

      METRIC = 'auto_deploy_building_package_state'
      PACKAGE_PROJECTS = [ReleaseTools::Project::CNGImage, ReleaseTools::Project::OmnibusGitlab].freeze

      def initialize
        @client = Metrics::Client.new
      end

      def package_building
        set_metric('running')
      end

      def package_built
        set_metric('success')

        unset_metric('running')
        unset_metric('failed')
      end

      def package_building_failed
        set_metric('failed')

        unset_metric('running')
      end

      def deployment_completed
        unset_metric('running')
        unset_metric('success')
        unset_metric('failed')
      end

      private

      # rubocop:disable Naming/AccessorMethodName
      def set_metric(state)
        unless current_package_is_newer_than_gstg_cny?
          logger.info('Not setting building_package_state metric since current package is not newer than on gstg-cny', state: state, current_version: product_version.version, version_on_gstg_cny: version_on_gstg_cny.version)
          return
        end

        logger.info('Setting building_package_state metric', state: state, current_version: product_version.version, version_on_gstg_cny: version_on_gstg_cny.version)

        @client.set(METRIC, 1, labels: state)
      end
      # rubocop:enable Naming/AccessorMethodName

      def unset_metric(pipeline_state)
        pipelines =
          PACKAGE_PROJECTS.map do |project|
            find_pipeline(project, version_on_gstg_cny, pipeline_state)
          end

        # Do not unset if there are pipelines in the given state
        if pipelines.any?
          logger.info('Not unsetting building_package_state metric since there are pipelines in the state', state: pipeline_state, current_version: product_version.version, version_on_gstg_cny: version_on_gstg_cny.version)
          return
        end

        logger.info('Unsetting building_package_state metric since there are no pipelines in the state', state: pipeline_state, current_version: product_version.version, version_on_gstg_cny: version_on_gstg_cny.version)

        @client.set(METRIC, 0, labels: pipeline_state)
      end

      def product_version
        @product_version ||= ProductVersion.new(AutoDeploy::Tag.current)
      end

      def current_package_is_newer_than_gstg_cny?
        product_version > version_on_gstg_cny
      end

      def version_on_gstg_cny
        @version_on_gstg_cny ||= ProductVersion.from_metadata_sha(deployment_on_gstg_cny.sha)
      end

      # Returns a pipeline (with version newer than what's on gstg-cny) in the given state.
      # Returns nil if no such pipeline can be found.
      def find_pipeline(project, min_version, state)
        pipeline =
          Retriable.with_context(:api) do
            GitlabDevClient.pipelines(
              project,
              name: 'AUTO_DEPLOY_BUILD_PIPELINE',
              status: state,
              per_page: 1
            ).first
          end

        return nil unless pipeline

        # Return nil if the pipeline version is older than the one on gstg-cny
        return nil if ProductVersion.from_auto_deploy_tag(pipeline.ref) <= min_version

        logger.info('Found new package in desired state', state: state, current_version: product_version.version, version_on_gstg_cny: min_version.version, pipeline: pipeline.web_url)

        pipeline
      end

      def deployment_on_gstg_cny
        Retriable.with_context(:api) do
          GitlabOpsClient.deployments(
            Project::Release::Metadata,
            'gstg-cny',
            status: 'success',
            order_by: 'id',
            sort: 'desc',
            opts: {
              per_page: 1
            }
          ).first
        end
      end
    end
  end
end
