module ForemanPuppet
  class HostgroupPuppetFacet < ApplicationRecord
    # ------ ANCESTRY ATTRIBUTES -------
    # This mimic nested attributes, that should probably be provided by Facets::HostgroupFacet

    class << self
      attr_reader :nested_attribute_fields

      def nested_attribute_for(*fields)
        @nested_attribute_fields ||= []
        @nested_attribute_fields |= fields
        @nested_attribute_fields.each do |field|
          # Example method
          # def inherited_compute_profile_id
          #   read_attribute(:compute_profile_id) || nested_compute_profile_id
          # end
          define_method "inherited_#{field}" do
            self[field] || nested(field)
          end

          # Example method - only override method generated by assocation if there is ancestry.
          # if ancestry.present?
          #   def compute_profile
          #    ComputeProfile.find_by_id(inherited_compute_profile_id)
          #  end
          # end
          next unless (md = field.to_s.match(/(\w+)_id$/))
          define_method md[1] do
            if hostgroup.ancestry.present?
              klass = "ForemanPuppet::#{md[1].classify}"
              klass = 'SmartProxy' if md[1] == 'puppet_proxy' || md[1] == 'puppet_ca_proxy'
              klass = 'Subnet::Ipv4' if md[1] == 'subnet'
              klass = 'Subnet::Ipv6' if md[1] == 'subnet6'
              klass.constantize.find_by(id: send("inherited_#{field}"))
            else
              # () is required.
              # Otherwise, get RuntimeError: implicit argument passing of super from method defined by define_method() is not supported.
              #                              Specify all arguments explicitly.
              super()
            end
          end
        end
      end
    end

    def nested(attr)
      return nil if hostgroup.ancestry.blank?
      Hostgroup.sort_by_ancestry(hostgroup.ancestors.joins(:puppet).where(HostgroupPuppetFacet.arel_table[attr.to_sym].not_eq(nil))).last&.puppet.try(attr)
    end

    delegate :parent_id, to: :hostgroup

    # and helpers
    def parent_facet_id
      parent_facet&.id
    end

    def parent_facet
      @parent_facet ||= hostgroup.parent_id && HostgroupPuppetFacet.find_by(hostgroup_id: hostgroup.parent_id)
    end
    # ------ END ANCESTRY -------

    audited associated_with: :hostgroup
    self.table_name = 'hostgroup_puppet_facets'

    include ForemanPuppet::PuppetFacetCommon
    include Facets::HostgroupFacet

    has_many :hostgroup_classes, dependent: :destroy
    has_many :puppetclasses, through: :hostgroup_classes

    before_save :remove_duplicated_nested_class

    nested_attribute_for :environment_id

    def all_config_groups
      (config_groups + parent_config_groups).uniq
    end

    def parent_config_groups
      return [] unless hostgroup.parent
      groups = []
      hostgroup.ancestors.each do |hostgroup|
        groups += hostgroup.puppet&.config_groups || []
      end
      groups.uniq
    end

    # the environment used by #clases nees to be self.environment and not self.parent.environment
    def parent_classes
      return [] unless parent_facet
      parent_facet.classes(environment)
    end

    def remove_duplicated_nested_class
      ancestor_hgs = hostgroup.ancestors.preload(puppet: :puppetclasses)
      self.puppetclasses -= ancestor_hgs.map { |ancestor| ancestor.puppet&.puppetclasses }.compact.flatten
    end
  end
end