# NOTE: When changing auto-join logic, make sure to update the `settings.auto_join_users_info` translation as well.
# frozen_string_literal: true

module Jobs
  class AutoManageChannelMemberships < ::Jobs::Base
    def execute(args)
      channel =
        ChatChannel.includes(:chatable).find_by(
          id: args[:chat_channel_id],
          auto_join_users: true,
          chatable_type: "Category",
        )

      return if !channel&.chatable

      processed =
        UserChatChannelMembership.where(
          chat_channel: channel,
          following: true,
          join_mode: UserChatChannelMembership.join_modes[:automatic],
        ).count

      auto_join_query(channel).find_in_batches do |batch|
        break if processed >= SiteSetting.max_chat_auto_joined_users

        starts_at = batch.first.query_user_id
        ends_at = batch.last.query_user_id

        Jobs.enqueue(
          :auto_join_channel_batch,
          chat_channel_id: channel.id,
          starts_at: starts_at,
          ends_at: ends_at,
        )

        processed += batch.size
      end

      # The Jobs::AutoJoinChannelBatch job will only do this recalculation
      # if it's operating on one user, so we need to make sure we do it for
      # the channel here once this job is complete.
      Chat::ChatChannelMembershipManager.new(channel).recalculate_user_count
    end

    private

    def auto_join_query(channel)
      category = channel.chatable

      users =
        User
          .real
          .activated
          .not_suspended
          .not_staged
          .distinct
          .select(:id, "users.id AS query_user_id")
          .where("last_seen_at > ?", 3.months.ago)
          .joins(:user_option)
          .where(user_options: { chat_enabled: true })
          .joins(<<~SQL)
            LEFT OUTER JOIN user_chat_channel_memberships uccm
            ON uccm.chat_channel_id = #{channel.id} AND
            uccm.user_id = users.id
          SQL
          .where("uccm.id IS NULL")

      if category.read_restricted?
        users =
          users
            .joins(:group_users)
            .joins("INNER JOIN category_groups cg ON cg.group_id = group_users.group_id")
            .where("cg.category_id = ?", channel.chatable_id)
      end

      users
    end
  end
end
