class TagNameSanitisationRule < ApplicationRecord
  include Discard::Model

  self.primary_key = :priority

  default_scope -> { kept }

  validates :source_pattern, presence: true, uniqueness: true

  validate :source_pattern_must_be_regexp

  class << self
    def sanitise(name) =
        rules.reduce(name.dup) { |name, (pattern, replacement)| name.gsub(pattern, replacement) }

    def apply!
      TagName.find_each do |tn|
        name = sanitise(tn.name)
        next if name == tn.name

        TagName.transaction do
          existing_tn = TagName.find_by(name:)
          if existing_tn
            existing_tn = existing_tn.canonical || existing_tn
            next if existing_tn.id == tn.id

            existing_tag = Tag.find_by(tag_name_id: existing_tn.id)
            source_tag = Tag.find_by(tag_name_id: tn.id)

            if existing_tag
              Tag.merge_tags!(existing_tag, source_tag) if tn.tag
            elsif source_tag
              source_tag.update_columns(tag_name_id: existing_tn.id, updated_at: Time.current)
            end
            tn.discard!

            next
          end

          # TagName 側の自動サニタイズを回避
          tn.update_columns(name:, updated_at: Time.current)
        end
      end
    end

    private

    def rules = kept.order(:priority).map { |r| [Regexp.new(r.source_pattern), r.replacement] }
  end

  private

  def source_pattern_must_be_regexp
    Regexp.new(source_pattern)
  rescue RegexpError
    errors.add :source_pattern, '変な正規表現だね〜（笑）'
  end
end
