# frozen_string_literal: true

module ReleaseTools
  module Services
    module PackagesStatus
      class Base
        include ::SemanticLogger::Loggable

        # version - ReleaseTools::Version
        # package_type - :tag, :internal
        def initialize(version, package_type: :tag)
          @version = version
          @results = {}
          @package_type = package_type
        end

        def execute
          pipelines.each do |pipeline|
            bridge = bridge_for(pipeline: pipeline)

            raise "No bridge job found for version #{version}, url: #{pipeline.web_url}, package_type: #{package_type}" unless bridge
            raise "No downstream pipeline created for version #{version}, url: #{pipeline.web_url}, package_type: #{package_type}" unless bridge.downstream_pipeline

            downstream_pipeline = downstream_pipeline(id: bridge.downstream_pipeline.id)

            store_status(downstream_pipeline)
          end

          @results
        end

        private

        attr_reader :version, :package_type

        def internal?
          package_type == :internal
        end

        def branch
          version.stable_branch
        end

        def bridge_job_name
          NotImplementedError
        end

        def project
          ReleaseTools::Project::OmnibusGitlab
        end

        def client
          ReleaseTools::GitlabDevClient
        end

        def tags
          [
            "#{version}+ee.0",
            "#{version}+ce.0"
          ]
        end

        def pipelines
          if internal?
            [fetch_tagless_pipeline]
          else
            fetch_pipeline_by_tags
          end
        end

        def fetch_pipeline_by_tags
          [].tap do |pipeline|
            tags.each do |tag|
              logger.info('Fetching pipelines for tag', tag: tag)

              pipeline << pipelines_for_tag(tag)
            end
          end.flatten
        end

        def fetch_tagless_pipeline
          logger.info('Fetching pipeline for branch', branch: branch)

          Retriable.with_context(:api) do
            client
              .pipelines(project, ref: branch)
              .select { |pipeline| pipeline.name == 'INTERNAL_RELEASE_BUILD_PIPELINE' }
              .max_by(&:created_at)
          end
        end

        def pipelines_for_tag(tag)
          Retriable.with_context(:api) do
            client
              .pipelines(project, ref: tag)
          end
        end

        def downstream_pipeline(id:)
          Retriable.with_context(:api) do
            client
              .pipeline(project, id)
          end
        end

        def bridge_for(pipeline:)
          logger.info('Fetching bridge', pipeline: pipeline.web_url)

          Retriable.with_context(:api) do
            client
              .pipeline_bridges(project, pipeline.id).find { |bridge| bridge.name == bridge_job_name }
          end
        end

        def store_status(downstream_pipeline)
          tag = downstream_pipeline.ref
          logger.info(
            "Downstream pipeline retrieved successfully for the tag: #{tag}",
            downstream_pipeline: downstream_pipeline.web_url,
            job_id: downstream_pipeline.id,
            status: downstream_pipeline.status
          )

          @results[tag] = downstream_pipeline.status
        end
      end
    end
  end
end
