# frozen_string_literal: true

module Git
  class WikiPushService < ::BaseService
    # Maximum number of change events we will process on any single push
    MAX_CHANGES = 100

    attr_reader :wiki

    def initialize(wiki, current_user, params)
      @wiki, @current_user, @params = wiki, current_user, params.dup
    end

    def execute
      # Execute model-specific callbacks
      wiki.after_post_receive

      process_changes
    end

    private

    def process_changes
      return unless can_process_wiki_events?

      push_changes.take(MAX_CHANGES).each do |change| # rubocop:disable CodeReuse/ActiveRecord
        next unless change.page.present?

        response = create_event_for(change)
        log_error(response.message) if response.error?
      end
    end

    def can_process_wiki_events?
      # TODO: Support activity events for group wikis
      # https://gitlab.com/gitlab-org/gitlab/-/issues/209306
      wiki.is_a?(ProjectWiki)
    end

    def push_changes
      default_branch_changes.flat_map do |change|
        raw_changes(change).map { |raw| Git::WikiPushService::Change.new(wiki, change, raw) }
      end
    end

    def raw_changes(change)
      wiki.repository.raw.raw_changes_between(change[:oldrev], change[:newrev])
    end

    def create_event_for(change)
      event_service.execute(
        change.last_known_slug,
        change.page,
        change.event_action,
        change.sha
      )
    end

    def event_service
      @event_service ||= WikiPages::EventCreateService.new(current_user)
    end

    def on_default_branch?(change)
      wiki.default_branch == ::Gitlab::Git.branch_name(change[:ref])
    end

    # See: [Gitlab::GitPostReceive#changes]
    def changes
      params[:changes] || []
    end

    def default_branch_changes
      @default_branch_changes ||= changes.select { |change| on_default_branch?(change) }
    end
  end
end

Git::WikiPushService.prepend_if_ee('EE::Git::WikiPushService')
