class SkinParent < ApplicationRecord
  belongs_to :child_skin, class_name: "Skin", touch: true
  belongs_to :parent_skin, class_name: "Skin"

  validates :position,
    uniqueness: {scope: [:child_skin_id, :parent_skin_id], message: ts("^Position has to be unique for each parent.")},
    numericality: {only_integer: true, greater_than: 0}

  validates_presence_of :child_skin, :parent_skin

  validate :no_site_parent
  def no_site_parent
    return unless parent_skin&.get_role == "site" && %w[override site].exclude?(child_skin.get_role)

    errors.add(:base, :site_parent, title: parent_skin.title)
  end

  validate :no_circular_skin
  def no_circular_skin
    if parent_skin == child_skin
      errors.add(:base, ts("^You can't make a skin its own parent"))
    end
    parent_ids = SkinParent.get_all_parent_ids(self.child_skin_id)
    if parent_ids.include?(self.parent_skin_id)
      errors.add(:base, ts("^%{parent_title} is already a parent of %{child_title}", child_title: child_skin.title, parent_title: parent_skin.title))
    end

    child_ids = SkinParent.get_all_child_ids(self.child_skin_id)
    if child_ids.include?(self.parent_skin_id)
      errors.add(:base, ts("^%{parent_title} is a child of %{child_title}", child_title: child_skin.title, parent_title: parent_skin.title))
    end

    # also don't allow duplication

  end

  # Takes as argument the ID of the skin to start at, and a block that should
  # take a list of skin IDs and produce a list of "adjacent" skin IDs (i.e.
  # parents or children).
  def self.search_skin_ids(root_id)
    found = Set.new([root_id])
    boundary = [root_id]

    until boundary.empty?
      new_boundary = yield boundary

      boundary = []

      new_boundary.each do |skin_id|
        boundary << skin_id if found.add?(skin_id)
      end
    end

    found.delete(root_id)
    found.to_a
  end

  def self.get_all_parent_ids(skin_id)
    search_skin_ids(skin_id) do |skin_ids|
      SkinParent.where(child_skin_id: skin_ids).pluck(:parent_skin_id)
    end
  end

  def self.get_all_child_ids(skin_id)
    search_skin_ids(skin_id) do |skin_ids|
      SkinParent.where(parent_skin_id: skin_ids).pluck(:child_skin_id)
    end
  end

   def parent_skin_title
     self.parent_skin.try(:title) || ""
   end

   def parent_skin_title=(title)
     self.parent_skin = Skin.find_by(title: title)
   end
end
