# frozen_string_literal: true

require 'yaml'

module ReleaseTools
  module ReleaseEnvironment
    class Environment
      include ::SemanticLogger::Loggable

      def initialize(version, suffix = nil)
        @version = ReleaseTools::Version.new(version)
        @suffix = suffix
        valid?
      end

      # Create a new release environment.
      #
      # A new environment directory is added to environments/ with the content
      # of an existing enviornment. The logic to deploy the right version to
      # the new environment is done by release-environment repo itself.
      #
      # @return [void]
      def create
        if exist?
          logger.info("The environment #{name} already exists. Skipping.")

          return
        end

        file_name = "environments/#{name}/environment.yaml"
        new_config = build_config(last_commit_on_stable_branch)

        logger.debug(new_config)

        return if SharedStatus.dry_run?

        Retriable.with_context(:api) do
          GitlabClient.create_file(
            project,
            file_name,
            project.default_branch,
            new_config,
            "[skip ci] Add new environment #{name}"
          )
        end
      end

      private

      attr_reader :version, :suffix

      def name
        @name ||= suffix.present? ? "#{@version.stable_branch}-#{suffix}" : @version.stable_branch
      end

      def exist?
        tree.any? { |hash| hash['name'] == name }
      end

      def tree
        @tree ||=
          Retriable.with_context(:api) do
            GitlabClient
              .tree(project, { path: 'environments' })
              .lazy_paginate
          end
      end

      def last_commit_on_stable_branch
        branch(version.stable_branch(ee: true))
          .last_commit['short_id']
      end

      # Package name is in the format <stable-branch>-<commit-id>
      # Replace package name from "shell: 16-9-stable-abc456" to "shell: 16-10-stable-efg123"
      def build_config(commit)
        config = latest_config.gsub(
          Regexp.new("#{latest_environment}-\\w+"),
          image_tag(commit)
        )

        yaml_data = YAML.load(config)

        if suffix == 'security'
          yaml_data['versions']['registry'] = security_registry
        end

        yaml_data.to_yaml
      end

      # Image tag is in the format <stable-branch-without-ee>-<commit-id>
      # E.g. 17-0-stable-8e06aedc
      def image_tag(commit)
        "#{version.stable_branch}-#{commit}"
      end

      def latest_config
        Retriable.with_context(:api) do
          GitlabClient.file_contents(
            project,
            "environments/#{latest_environment}/environment.yaml",
            project.default_branch
          )
        end
      end

      def latest_environment
        @latest_environment ||= begin
          versions_hash = {}

          tree.each do |hash|
            branch_name = hash.to_h.fetch('name')
            version = branch(branch_name).version
            versions_hash[version] = branch_name
          end

          logger.info('Sorting versions', versions: versions_hash.keys, branches: versions_hash.values)

          latest_version = ReleaseTools::Versions.sort(versions_hash.keys).last

          versions_hash[latest_version]
        end
      end

      def branch(name)
        ReleaseTools::Branch.new(name: name, project: ReleaseTools::Project::GitlabEe)
      end

      def project
        ReleaseTools::Project::Infrastructure::ReleaseEnvironment
      end

      def valid?
        raise ArgumentError, "Invalid version: #{version}" unless ReleaseTools::Version.new(version).valid?
      end

      def security_registry
        'registry.gitlab.com/gitlab-org/security/charts/components/images'
      end
    end
  end
end
