class TagName < ApplicationRecord
  include MyDiscard

  has_one :tag
  has_one :wiki_page

  belongs_to :canonical, class_name: 'TagName', optional: true
  has_many :aliases, class_name: 'TagName', foreign_key: :canonical_id

  validates :name, presence: true, length: { maximum: 255 }, uniqueness: true

  validate :canonical_must_be_canonical
  validate :alias_name_must_not_have_prefix
  validate :canonical_must_not_be_present_with_tag_or_wiki_page
  validate :name_must_be_sanitised

  def self.canonicalise names
    names = Array(names).map { |n| n.to_s.strip }.reject(&:blank?)
    return [] if names.blank?

    tns = TagName.includes(:canonical).where(name: names).index_by(&:name)

    names.map { |name| tns[name]&.canonical&.name || name }.uniq
  end

  private

  def canonical_must_be_canonical
    if canonical&.canonical_id?
      errors.add :canonical, 'canonical は実体を示す必要があります．'
    end
  end

  def alias_name_must_not_have_prefix
    if canonical_id? && name.to_s.include?(':')
      errors.add :name, 'エーリアス名にプレフィクスを含むことはできません．'
    end
  end

  def canonical_must_not_be_present_with_tag_or_wiki_page
    if canonical_id? && (tag || wiki_page)
      errors.add :canonical, 'タグもしくは Wiki の参照がある名前はエーリアスになれません．'
    end
  end

  def name_must_be_sanitised
    if name? && name != TagNameSanitisationRule.sanitise(name)
      errors.add :name, '名前に使用できない文字が含まれてゐます．'
    end
  end
end
