class ExternalWork < ApplicationRecord
  include Bookmarkable
  include Filterable
  include Searchable

  has_many :related_works, as: :parent

  belongs_to :language

  # .duplicate.count.size returns the number of URLs with multiple external works
  scope :duplicate, -> { group(:url).having("count(DISTINCT id) > 1") }

  scope :for_blurb, -> { includes(:language, :tags) }

  AUTHOR_LENGTH_MAX = 500

  validates_presence_of :title
  validates_length_of :title, minimum: ArchiveConfig.TITLE_MIN,
                              too_short: ts("must be at least %{min} characters long.",
                                            min: ArchiveConfig.TITLE_MIN)
  validates_length_of :title, maximum: ArchiveConfig.TITLE_MAX,
                              too_long: ts("must be less than %{max} characters long.",
                                           max: ArchiveConfig.TITLE_MAX)

  validates_length_of :summary, allow_blank: true, maximum: ArchiveConfig.SUMMARY_MAX,
                                too_long: ts("must be less than %{max} characters long.",
                                             max: ArchiveConfig.SUMMARY_MAX)

  validates :author, presence: { message: ts("can't be blank") }
  validates_length_of :author, maximum: AUTHOR_LENGTH_MAX,
                               too_long: ts("must be less than %{max} characters long.",
                                            max: AUTHOR_LENGTH_MAX)

  validates :user_defined_tags_count,
            at_most: { maximum: proc { ArchiveConfig.USER_DEFINED_TAGS_MAX } }

  # TODO: External works should have fandoms, but they currently don't get added through the
  # post new work form so we can't validate them
  #validates_presence_of :fandoms

  before_validation :cleanup_url
  # i18n-tasks-use t("errors.attributes.url.invalid")
  validates :url, presence: true, url_format: true, url_active: true
  def cleanup_url
    self.url = Addressable::URI.heuristic_parse(self.url) if self.url
  rescue Addressable::URI::InvalidURIError
    # url_format validation creates the error message
  end

  # Allow encoded characters to display correctly in titles
  def title
    read_attribute(:title).try(:html_safe)
  end

  ########################################################################
  # VISIBILITY
  ########################################################################
  # Adapted from work.rb

  scope :visible_to_all, -> { where(hidden_by_admin: false) }
  scope :visible_to_registered_user, -> { where(hidden_by_admin: false) }
  scope :visible_to_admin, -> { where("") }

  # a complicated dynamic scope here:
  # if the user is an Admin, we use the "visible_to_admin" scope
  # if the user is not a logged-in User, we use the "visible_to_all" scope
  # otherwise, we use a join to get userids and then get all posted works that are either unhidden OR belong to this user.
  # Note: in that last case we have to use select("DISTINCT works.") because of cases where the same user appears twice
  # on a work.
  scope :visible_to_user, lambda {|user| user.is_a?(Admin) ? visible_to_admin : visible_to_all}

  # Use the current user to determine what external works are visible
  scope :visible, -> { visible_to_user(User.current_user) }

  # Visible unless we're hidden by admin, in which case only an Admin can see.
  def visible?(user=User.current_user)
    self.hidden_by_admin? ? user.kind_of?(Admin) : true
  end

  # Visibility has changed, which means we need to reindex
  # the external work's bookmarker pseuds, to update their bookmark counts.
  def should_reindex_pseuds?
    pertinent_attributes = %w[id hidden_by_admin]
    destroyed? || (saved_changes.keys & pertinent_attributes).present?
  end

  ######################
  # SEARCH
  ######################

  def bookmarkable_json
    as_json(
      root: false,
      only: [
        :title, :summary, :hidden_by_admin, :created_at
      ],
      methods: [
        :posted, :restricted, :tag, :filter_ids, :rating_ids,
        :archive_warning_ids, :category_ids, :fandom_ids, :character_ids,
        :relationship_ids, :freeform_ids, :creators, :revised_at
      ]
    ).merge(
      language_id: language&.short,
      bookmarkable_type: "ExternalWork",
      bookmarkable_join: { name: "bookmarkable" }
    )
  end

  def posted
    true
  end
  alias_method :posted?, :posted

  def restricted
    false
  end
  alias_method :restricted?, :restricted

  def creators
    [author]
  end

  def revised_at
    created_at
  end
end
