module Search
  class Comment
    ATTRIBUTES = [
      "COALESCE(articles.published, false) AS commentable_published",
      "COALESCE(articles.title, '') AS commentable_title",
      "comments.body_markdown",
      "comments.commentable_id",
      "comments.commentable_type",
      "comments.created_at",
      "comments.id AS id",
      "comments.public_reactions_count",
      "comments.score",
      "comments.user_id",
    ].freeze
    private_constant :ATTRIBUTES

    DEFAULT_PER_PAGE = 60
    private_constant :DEFAULT_PER_PAGE

    DEFAULT_SORT_BY = "comments.score".freeze
    private_constant :DEFAULT_SORT_BY

    DEFAULT_SORT_DIRECTION = :desc
    private_constant :DEFAULT_SORT_DIRECTION

    MAX_PER_PAGE = 120 # to avoid querying too many items, we set a maximum amount for a page
    private_constant :MAX_PER_PAGE

    def self.search_documents(
      page: 0,
      per_page: DEFAULT_PER_PAGE,
      sort_by: DEFAULT_SORT_BY,
      sort_direction: DEFAULT_SORT_DIRECTION,
      term: nil
    )
      sort_by ||= DEFAULT_SORT_BY
      # The UI and serializer rename created_at (the actual DB column name) to
      # published_at
      sort_by = "comments.created_at" if sort_by == "published_at"

      sort_direction ||= DEFAULT_SORT_DIRECTION

      # NOTE: [@rhymes/atsmith813] we should eventually update the frontend
      # to start from page 1
      page = page.to_i + 1
      per_page = [(per_page || DEFAULT_PER_PAGE).to_i, MAX_PER_PAGE].min

      relation = ::Comment
        .includes(:user)
        .where(
          deleted: false,
          hidden_by_commentable_user: false,
          commentable_type: "Article",
        )
        .joins("join articles on articles.id = comments.commentable_id")
        .where("articles.published": true)

      relation = relation.search_comments(term).with_pg_search_highlight if term.present?

      relation = relation.select(*ATTRIBUTES).reorder("#{sort_by}": sort_direction)

      results = relation.page(page).per(per_page)

      serialize(results)
    end

    def self.serialize(results)
      Search::CommentSerializer
        .new(results, is_collection: true)
        .serializable_hash[:data]
        .pluck(:attributes)
    end
    private_class_method :serialize
  end
end
