class SearchShixunService < ApplicationService
  include ElasticsearchAble

  attr_reader :user, :params

  def initialize(user, params)
    @user   = user
    @params = params
  end

  def call
    Shixun.search(keyword,
                  fields: search_fields,
                  where: where_clauses,
                  order: order_clauses,
                  includes: includes_clauses,
                  page: page,
                  per_page: per_page)
  end

  private

  def tag_filter_shixun_ids
    return [] if params[:tag_level].to_i == 0 || params[:tag_id].blank?

    case params[:tag_level].to_i
    when 1 then
      Repertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires)
        .pluck('shixun_tag_repertoires.shixun_id')
    when 2 then
      SubRepertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires)
        .pluck('shixun_tag_repertoires.shixun_id')
    when 3 then
      TagRepertoire.find(params[:tag_id]).shixun_tag_repertoires.pluck(:shixun_id)
    else
      []
    end
  end

  def user_filter_shixun_ids
    return [] if params[:order_by] != 'mine'

    user.shixun_members.pluck(:shixun_id) + user.myshixuns.pluck(:shixun_id)
  end

  def keyword
    params[:keyword].to_s.strip.presence || '*'
  end

  def search_fields
    %w(name^10 author_name challenge_names description challenge_tag_names)
  end

  def where_clauses
    hash = {}

    ids = user_filter_shixun_ids + tag_filter_shixun_ids
    hash[:id] = ids if ids.present?

    if params[:order_by] == 'mine'
      hash[:status] = { not: -1 }
    else
      hash.merge!(hidden: false, status: 2)
    end

    unless params[:status].to_i.zero?
      params[:status] = [0, 1] if params[:status].to_i == 1
      hash[:status] = params[:status]
    end

    hash[:trainee] = params[:diff].to_i unless params[:diff].to_i.zero?

    hash
  end

  def includes_clauses
    []
  end

  def order_clauses
    hash = { _score: :desc }
    publish_order = { type: 'number', order: :desc, script: 'doc["status"].value=="2" ? 1 : 0' }

    sort = params[:sort].to_s.strip == 'asc' ? 'asc' : 'desc'
    clauses =
      case params[:order_by].presence
      when 'new'  then { _script: publish_order, created_at: sort }
      when 'hot'  then { _script: publish_order, myshixuns_count: sort }
      when 'mine' then { created_at: sort }
      else { _script: publish_order, publish_time: sort }
      end
    hash.merge!(clauses)

    hash
  end
end