# frozen_string_literal: true

module Clusters
  module Applications
    class PrometheusConfigService
      def initialize(project, cluster, app)
        @project = project
        @cluster = cluster
        @app = app
      end

      def execute(config = {})
        if has_alerts?
          generate_alert_manager(config)
        else
          reset_alert_manager(config)
        end
      end

      private

      attr_reader :project, :cluster, :app

      def reset_alert_manager(config)
        config = set_alert_manager_enabled(config, false)
        config.delete('alertmanagerFiles')
        config['serverFiles'] ||= {}
        config['serverFiles']['alerts'] = {}

        config
      end

      def generate_alert_manager(config)
        config = set_alert_manager_enabled(config, true)
        config = set_alert_manager_files(config)

        set_alert_manager_groups(config)
      end

      def set_alert_manager_enabled(config, enabled)
        config['alertmanager'] ||= {}
        config['alertmanager']['enabled'] = enabled

        config
      end

      def set_alert_manager_files(config)
        config['alertmanagerFiles'] = {
          'alertmanager.yml' => {
            'receivers' => alert_manager_receivers_params,
            'route' => alert_manager_route_params
          }
        }

        config
      end

      def set_alert_manager_groups(config)
        config['serverFiles'] ||= {}
        config['serverFiles']['alerts'] ||= {}
        config['serverFiles']['alerts']['groups'] ||= []

        environments_with_alerts.each do |env_name, alerts|
          index = config['serverFiles']['alerts']['groups'].find_index do |group|
            group['name'] == env_name
          end

          if index
            config['serverFiles']['alerts']['groups'][index]['rules'] = alerts
          else
            config['serverFiles']['alerts']['groups'] << {
              'name' => env_name,
              'rules' => alerts
            }
          end
        end

        config
      end

      def alert_manager_receivers_params
        [
          {
            'name' => 'gitlab',
            'webhook_configs' => [
              {
                'url' => notify_url,
                'send_resolved' => true,
                'http_config' => {
                  'bearer_token' => alert_manager_token
                }
              }
            ]
          }
        ]
      end

      def alert_manager_token
        app.generate_alert_manager_token!

        app.alert_manager_token
      end

      def alert_manager_route_params
        {
          'receiver' => 'gitlab',
          'group_wait' => '30s',
          'group_interval' => '5m',
          'repeat_interval' => '4h'
        }
      end

      def notify_url
        ::Gitlab::Routing.url_helpers
          .notify_project_prometheus_alerts_url(project, format: :json)
      end

      def has_alerts?
        environments_with_alerts.values.flatten(1).any?
      end

      def environments_with_alerts
        @environments_with_alerts ||=
          environments.each_with_object({}) do |environment, hash|
            name = rule_name(environment)
            hash[name] = alerts(environment)
          end
      end

      def rule_name(environment)
        "#{environment.name}.rules"
      end

      def alerts(environment)
        variables = Gitlab::Prometheus::QueryVariables.call(environment)
        alerts = Projects::Prometheus::AlertsFinder
          .new(environment: environment)
          .execute

        alerts.map do |alert|
          substitute_query_variables(alert.to_param, variables)
        end
      end

      def substitute_query_variables(hash, variables)
        hash['expr'] %= variables
        hash
      end

      def environments
        project.environments_for_scope(cluster.environment_scope)
      end
    end
  end
end
