# == Schema Information
#
# Table name: articles
#
#  id                    :bigint           not null, primary key
#  content               :text
#  description           :text
#  meta                  :jsonb
#  slug                  :string           not null
#  status                :integer
#  title                 :string
#  views                 :integer
#  created_at            :datetime         not null
#  updated_at            :datetime         not null
#  account_id            :integer          not null
#  associated_article_id :bigint
#  author_id             :bigint
#  category_id           :integer
#  folder_id             :integer
#  portal_id             :integer          not null
#
# Indexes
#
#  index_articles_on_associated_article_id  (associated_article_id)
#  index_articles_on_author_id              (author_id)
#  index_articles_on_slug                   (slug) UNIQUE
#
class Article < ApplicationRecord
  include PgSearch::Model

  has_many :associated_articles,
           class_name: :Article,
           foreign_key: :associated_article_id,
           dependent: :nullify,
           inverse_of: 'root_article'

  belongs_to :root_article,
             class_name: :Article,
             foreign_key: :associated_article_id,
             inverse_of: :associated_articles,
             optional: true
  belongs_to :account
  belongs_to :category
  belongs_to :portal
  belongs_to :author, class_name: 'User'

  before_validation :ensure_account_id
  before_validation :ensure_article_slug

  validates :account_id, presence: true
  validates :category_id, presence: true
  validates :author_id, presence: true
  validates :title, presence: true
  validates :content, presence: true

  enum status: { draft: 0, published: 1, archived: 2 }

  scope :search_by_category_slug, ->(category_slug) { where(categories: { slug: category_slug }) if category_slug.present? }
  scope :search_by_category_locale, ->(locale) { where(categories: { locale: locale }) if locale.present? }
  scope :search_by_author, ->(author_id) { where(author_id: author_id) if author_id.present? }
  scope :search_by_status, ->(status) { where(status: status) if status.present? }

  # TODO: if text search slows down https://www.postgresql.org/docs/current/textsearch-features.html#TEXTSEARCH-UPDATE-TRIGGERS
  pg_search_scope(
    :text_search,
    against: %i[
      title
      description
      content
    ],
    using: {
      tsearch: {
        prefix: true
      }
    }
  )

  def self.search(params)
    records = joins(
      :category
    ).search_by_category_slug(
      params[:category_slug]
    ).search_by_category_locale(params[:locale]).search_by_author(params[:author_id]).search_by_status(params[:status])

    records = records.text_search(params[:query]) if params[:query].present?
    records
  end

  def associate_root_article(associated_article_id)
    article = portal.articles.find(associated_article_id) if associated_article_id.present?

    return if article.nil?

    root_article_id = self.class.find_root_article_id(article)

    update(associated_article_id: root_article_id) if root_article_id.present?
  end

  # Make sure we always associate the parent's associated id to avoid the deeper associations od articles.
  def self.find_root_article_id(article)
    article.associated_article_id || article.id
  end

  def draft!
    update(status: :draft)
  end

  private

  def ensure_account_id
    self.account_id = portal&.account_id
  end

  def ensure_article_slug
    self.slug ||= "#{Time.now.utc.to_i}-#{title.underscore.parameterize(separator: '-')}" if title.present?
  end
end
