<commit_before>class FilterWipsQuery
  attr_accessor :product_wips, :user, :filters

  def self.call(product_wips, user, filters)
    new(product_wips, user, filters).filter_wips
  end

  def initialize(product_wips, user, filters)
    self.product_wips = product_wips
    self.user = user
    self.filters = filters
  end

  def filter_wips
    apply_filters(product_wips_with_users)
  end

  def product_wips_with_users
    product_wips.includes(:user)
  end

  def apply_filters(query)
    filter_clauses.inject(query) do |query, clause|
      query.merge(clause)
    end
  end

  def filter_clauses
    [state_filter, tag_filter, mark_filter, doing_filter, created_filter,
     commented_filter, mentioned_filter, query_filter, user_filter, sort_order,
     page_selection].compact
  end

  def state_filter
    return unless states.present?

    expanded_states = states.flat_map do |state|
      case state
      when 'open'
        ['open', 'awarded']
      when 'doing'
        ['allocated']
      when 'reviewing'
        'reviewing'
      when 'done'
        ['closed', 'resolved']
      end
    end

    Wip.where(state: expanded_states)
  end

  def tag_filter
    return unless tags.present?

    Wip.joins(:tags).where(wip_tags: { name: tags }).uniq
  end

  def mark_filter
    return unless marks.present?

    Wip.joins(:marks).where(marks: { name: marks }).uniq
  end

  def doing_filter
    return unless doing.present?

    doing_ids = User.where(username: doing).pluck(:id)
    Task.joins(:wip_workers).where(wip_workers: { user_id: doing_ids }).uniq
  end

  def created_filter
    return unless created.present?

    created_ids = User.where(username: created).pluck(:id)
    Wip.where(user_id: created_ids)
  end

  def commented_filter
    return unless commented.present?

    commented_ids = User.where(username: commented).pluck(:id)
    Wip.joins(:comments).where(user_id: commented_ids).uniq
  end

  def mentioned_filter
    return unless mentioned.present?

    mentioned_wildcards = mentioned.map { |m| "%@#{m}%" }
    Wip.joins(:comments).where('body ILIKE ANY (ARRAY[?])', mentioned_wildcards).uniq
  end

  def query_filter
    return unless query.present?

    Wip.where('title ILIKE ?', "%#{query}%")
  end

  def user_filter
    case user_params
    when 'started'
      user.wips
    when 'assigned'
      user.wips_working_on
    when 'following'
      user.wips_watched
    when 'awarded'
      # TODO: Backfill awards and swap with a simpler query
      Wip.joins(events: :event).
        where(events: { type: 'Event::Win' }).
        where(events_events: { user_id: user.id }).
        order('events.created_at DESC')
    when 'commented'
      user.wips_commented_on
    else # all
      Wip.all
    end
  end

  def sort_order
    case sort
    when 'most_valuable'
      Wip.order('total_coins_cache DESC NULLS LAST')
    when 'least_valuable'
      Wip.order('total_coins_cache ASC')
    when 'newest'
      Wip.order('wips.created_at DESC')
    when 'oldest'
      Wip.order('wips.created_at ASC')
    when 'recently_updated'
      Wip.order('wips.updated_at DESC')
    when 'least_recently_updated'<commit_msg>Fix awarded filter<commit_after>class FilterWipsQuery
  attr_accessor :product_wips, :user, :filters

  def self.call(product_wips, user, filters)
    new(product_wips, user, filters).filter_wips
  end

  def initialize(product_wips, user, filters)
    self.product_wips = product_wips
    self.user = user
    self.filters = filters
  end

  def filter_wips
    apply_filters(product_wips_with_users)
  end

  def product_wips_with_users
    product_wips.includes(:user)
  end

  def apply_filters(query)
    filter_clauses.inject(query) do |query, clause|
      query.merge(clause)
    end
  end

  def filter_clauses
    [state_filter, tag_filter, mark_filter, doing_filter, created_filter,
     commented_filter, mentioned_filter, query_filter, user_filter, sort_order,
     page_selection].compact
  end

  def state_filter
    return unless states.present?

    expanded_states = states.flat_map do |state|
      case state
      when 'open'
        ['open', 'awarded']
      when 'doing'
        ['allocated']
      when 'reviewing'
        'reviewing'
      when 'done'
        ['closed', 'resolved']
      end
    end

    Wip.where(state: expanded_states)
  end

  def tag_filter
    return unless tags.present?

    Wip.joins(:tags).where(wip_tags: { name: tags }).uniq
  end

  def mark_filter
    return unless marks.present?

    Wip.joins(:marks).where(marks: { name: marks }).uniq
  end

  def doing_filter
    return unless doing.present?

    doing_ids = User.where(username: doing).pluck(:id)
    Task.joins(:wip_workers).where(wip_workers: { user_id: doing_ids }).uniq
  end

  def created_filter
    return unless created.present?

    created_ids = User.where(username: created).pluck(:id)
    Wip.where(user_id: created_ids)
  end

  def commented_filter
    return unless commented.present?

    commented_ids = User.where(username: commented).pluck(:id)
    Wip.joins(:comments).where(user_id: commented_ids).uniq
  end

  def mentioned_filter
    return unless mentioned.present?

    mentioned_wildcards = mentioned.map { |m| "%@#{m}%" }
    Wip.joins(:comments).where('body ILIKE ANY (ARRAY[?])', mentioned_wildcards).uniq
  end

  def query_filter
    return unless query.present?

    Wip.where('title ILIKE ?', "%#{query}%")
  end

  def user_filter
    case user_params
    when 'started'
      user.wips
    when 'assigned'
      user.wips_working_on
    when 'following'
      user.wips_watched
    when 'awarded'
      # TODO: Backfill awards and swap with a simpler query
      Wip.joins(awards: :wip).
          where(awards: { winner_id: user.id }).
          order('wips.created_at DESC')
    when 'commented'
      user.wips_commented_on
    else # all
      Wip.all
    end
  end

  def sort_order
    case sort
    when 'most_valuable'
      Wip.order('total_coins_cache DESC NULLS LAST')
    when 'least_valuable'
      Wip.order('total_coins_cache ASC')
    when 'newest'
      Wip.order('wips.created_at DESC')
    when 'oldest'
      Wip.order('wips.created_at ASC')
    when 'recently_updated'
      Wip.order('wips.updated_at DESC')
    when 'least_recently_updated'
{'fraction_non_alphanumeric': 0.099601593625498, 'fraction_numerical': 0.0, 'mean_word_length': 3.099281515349445, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4488574', 'n_tokens_mistral': 2156, 'n_tokens_neox': 2083, 'n_words': 468}