# frozen_string_literal: true

# Provides helper methods for listing Users
class Members::ListService
  class << self
    def list(params)
      @query = User.includes(:profile, :group, :statistic_profile)
                   .joins(:profile,
                          :statistic_profile,
                          :group,
                          :roles,
                          'LEFT JOIN (
                              SELECT *
                              FROM "subscriptions" AS s1
                              INNER JOIN (
                                  SELECT MAX("created_at") AS "s2_created_at", "statistic_profile_id" AS "s2_statistic_profile_id"
                                  FROM "subscriptions"
                                  GROUP BY "statistic_profile_id"
                              ) AS s2
                              ON "s1"."statistic_profile_id" =  "s2"."s2_statistic_profile_id"
                              WHERE "s1"."expiration_date" > now()::date
                          ) AS "subscriptions" ON "subscriptions"."statistic_profile_id" = "statistic_profiles"."id" ' \
                          'LEFT JOIN "plans" ON "plans"."id" = "subscriptions"."plan_id"')
                   .where("users.is_active = 'true' AND roles.name = 'member'")
                   .order(list_order(params))

      # ILIKE => PostgreSQL case-insensitive LIKE
      if params[:search].size.positive?
        @query = @query.where('users.username ILIKE :search OR ' \
                              'profiles.first_name ILIKE :search OR ' \
                              'profiles.last_name ILIKE :search OR '  \
                              'profiles.phone ILIKE :search OR ' \
                              'email ILIKE :search OR ' \
                              'groups.name ILIKE :search OR ' \
                              'plans.base_name ILIKE :search', search: "%#{params[:search]}%")
      end

      filter = params[:filter].presence_in(%w[inactive_for_3_years not_confirmed]) || nil
      @query = @query.send(filter) if filter

      @query
    end

    def search(current_user, query, subscription, include_admins = 'false')
      members = User.includes(:profile, :statistic_profile)
                    .joins(:profile,
                           :statistic_profile,
                           :roles,
                           'LEFT JOIN "subscriptions" ON "subscriptions"."statistic_profile_id" = "statistic_profiles"."id" AND ' \
                           '"subscriptions"."created_at" = ( ' \
                             'SELECT max("created_at") ' \
                             'FROM "subscriptions" ' \
                             'WHERE "statistic_profile_id" = "statistic_profiles"."id")')
                    .where("users.is_active = 'true'")
                    .limit(50)
      query.downcase.split(' ').each do |word|
        members = members.where('lower(f_unaccent(profiles.first_name)) ~ :search OR ' \
                                'lower(f_unaccent(profiles.last_name)) ~ :search',
                                search: word)
      end


      if current_user.member?
        # non-admin can only retrieve users with "public profiles"
        members = members.where("users.is_allow_contact = 'true'")
      elsif subscription == 'true'
        # only admins have the ability to filter by subscription
        members = members.where('subscriptions.id IS NOT NULL AND subscriptions.expiration_date >= :now', now: Date.today.to_s)
      elsif subscription == 'false'
        members = members.where('subscriptions.id IS NULL OR subscriptions.expiration_date < :now', now: Date.today.to_s)
      end

      members = members.where("roles.name = 'member' OR roles.name = 'manager'") if include_admins == 'false' || include_admins.blank?

      members.to_a.filter(&:valid?)
    end

    private

    def list_order(params)
      direction = (params[:order_by][0] == '-' ? 'DESC' : 'ASC')
      order_key = (params[:order_by][0] == '-' ? params[:order_by][1, params[:order_by].size] : params[:order_by])
      limit = params[:size]
      offset = ((params[:page]&.to_i || 1) - 1) * (params[:size]&.to_i || 1)

      order_key = case order_key
                  when 'username'
                    'users.username'
                  when 'last_name'
                    'profiles.last_name'
                  when 'first_name'
                    'profiles.first_name'
                  when 'email'
                    'users.email'
                  when 'phone'
                    'profiles.phone'
                  when 'group'
                    'groups.name'
                  when 'plan'
                    'plans.base_name'
                  else
                    'users.id'
                  end

      "#{order_key} #{direction}, users.id ASC LIMIT #{limit} OFFSET #{offset}"
    end
  end
end