# frozen_string_literal: true

module ReleaseTools
  module PublicRelease
    class KasRelease
      include Release

      attr_reader :version, :client, :release_metadata

      def initialize(
        version,
        client: GitlabClient,
        release_metadata: ReleaseMetadata.new
      )
        @version = version.to_ce
        @client = client
        @release_metadata = release_metadata
      end

      def execute
        if Feature.disabled?(:release_the_kas)
          logger.info(':release_the_kas feature is disabled')

          return
        end

        logger.info(
          'Starting KAS release',
          version: version
        )

        create_target_branch

        if SharedStatus.dry_run?
          logger.info('This is a dry run, tags and release metadata will not be created')

          return
        end

        update_versions

        compile_changelog

        tag = create_tag

        if Feature.enabled?(:tag_kas_after_monthly_release)
          update_version_for_default_branch
          create_tag_for_default_branch
        end

        add_release_metadata(tag)
        notify_slack(project, version)
      end

      private

      def update_versions
        logger.info(
          'Updating version files',
          project: project_path,
          version: version
        )

        commit_version_files(
          target_branch,
          { 'VERSION' => version.to_s }
        )
      end

      # Update the version file for the default branch only for the monthly releases.
      # This will ensure that the default branch is always up-to-date with the latest RC version.
      def update_version_for_default_branch
        return unless version.monthly?

        logger.info(
          'Updating a version file for the default branch for a monthly release',
          project: project_path,
          version: next_rc_version
        )

        commit_version_files(
          project.default_branch,
          { 'VERSION' => next_rc_version }
        )
      end

      def next_rc_version
        @next_rc_version ||= ReleaseTools::Version.new(version.next_milestone).to_rc
      end

      def create_tag_for_default_branch
        return unless version.monthly?

        tag_name = ReleaseTools::Version.new(next_rc_version).tag

        logger.info('Creating tag', tag: tag_name, project: project_path)

        client.find_or_create_tag(
          project_path,
          tag_name,
          project.default_branch,
          message: "Version #{tag_name}"
        )
      end

      def compile_changelog
        return if version.rc?

        logger.info('Compiling changelog', project: project_path)

        # NOTE: we do not want to skip ci for changelog commits for KAS
        # because the KAS repository also contains agentk which is built
        # in the canonical gitlab-agent repository. The changelog commit
        # is often the commit that is tagged for a release for which we
        # require the pipeline to run so that agentk is properly released.
        ChangelogCompiler
          .new(project_path, client: client)
          .compile(version, branch: target_branch, skip_ci: false)
      end

      def create_tag
        logger.info('Creating tag', tag: tag_name, project: project_path)

        client.find_or_create_tag(
          project_path,
          tag_name,
          target_branch,
          message: "Version #{tag_name}"
        )
      end

      def add_release_metadata(tag)
        meta_version = version.to_normalized_version

        logger.info(
          'Recording release data',
          project: project_path,
          version: meta_version,
          sha: tag.commit.id,
          tag: true
        )

        release_metadata.add_release(
          name: project.metadata_project_name,
          version: meta_version,
          sha: tag.commit.id,
          ref: tag.name,
          tag: true
        )
      end

      def project
        Project::Kas
      end
    end
  end
end
