# frozen_string_literal: true

module Thredded
  class PrivateTopic < ActiveRecord::Base
    include Thredded::TopicCommon

    scope :for_user, ->(user) { joins(:private_users).merge(PrivateUser.where(user_id: user.id)) }

    extend FriendlyId
    friendly_id :slug_candidates,
                use:            %i[history reserved],
                # Avoid route conflicts
                reserved_words: ::Thredded::FriendlyIdReservedWordsAndPagination.new(%w[new])

    belongs_to :user,
               class_name: Thredded.user_class_name,
               inverse_of: :thredded_private_topics,
               **(Thredded.rails_gte_51? ? { optional: true } : {})
    belongs_to :user_detail,
               primary_key:   :user_id,
               foreign_key:   :user_id,
               inverse_of:    :private_topics,
               **(Thredded.rails_gte_51? ? { optional: true } : {})

    has_many :posts,
             class_name:  'Thredded::PrivatePost',
             foreign_key: :postable_id,
             inverse_of:  :postable,
             dependent:   :destroy
    has_one :first_post, -> { order_oldest_first },
            class_name:  'Thredded::PrivatePost',
            foreign_key: :postable_id
    has_many :private_users, inverse_of: :private_topic
    has_many :users, through: :private_users
    has_many :user_read_states,
             class_name: 'Thredded::UserPrivateTopicReadState',
             foreign_key: :postable_id,
             inverse_of: :postable,
             dependent: :destroy

    validates_each :users do |model, _attr, users|
      # Must include the creator + at least one other user
      if users.length < 2
        model.errors.add(:user_ids, I18n.t('thredded.private_topics.errors.user_ids_length'))
      end
      unless users.include?(model.user)
        # This never happens in the UI, so we don't need to i18n the message.
        model.errors.add(:user_ids, 'must include in user_ids')
      end
    end

    before_validation :ensure_user_in_private_users

    # Finds the topic by its slug or ID, or raises Thredded::Errors::PrivateTopicNotFound.
    # @param slug_or_id [String]
    # @return [Thredded::PrivateTopic]
    # @raise [Thredded::Errors::PrivateTopicNotFound] if the topic with the given slug does not exist.
    def self.friendly_find!(slug_or_id)
      friendly.find(slug_or_id)
    rescue ActiveRecord::RecordNotFound
      raise Thredded::Errors::PrivateTopicNotFound
    end

    def public?
      false
    end

    def should_generate_new_friendly_id?
      title_changed?
    end

    def normalize_friendly_id(input)
      Thredded.slugifier.call(input.to_s)
    end

    def user_names
      Thredded.user_class.where(id: user_ids).pluck(Thredded.user_display_name_method).join(', ')
    end

    private

    def slug_candidates
      [
        :title,
        [:title, '-topic']
      ]
    end

    def ensure_user_in_private_users
      users << user if user.present? && !users.include?(user)
    end
  end
end
