require_relative '../models/manageiq/providers/inventory/persister.rb'

class TestContainersPersister < ManageIQ::Providers::Inventory::Persister
  def initialize_inventory_collections
    %i(containers
       container_build_pods
       container_groups
       container_image_registries
       container_images
       container_nodes
       container_projects
       container_replicators).each do |name|

      add_collection(container, name)
    end

    initialize_container_conditions

    initialize_custom_attributes
  end

  protected

  def initialize_container_conditions
    # %i(container_groups
    #    container_nodes).each do |name|
    #   add_container_conditions(manager, name)
    # end
  end

  def initialize_custom_attributes
    # %i(container_nodes
    #    container_projects).each do |name|
    #   add_custom_attributes(name, %w(labels additional_attributes))
    # end
    #
    # %i(container_groups).each do |name|
    #   add_custom_attributes(name, %w(labels node_selectors))
    # end
    #
    # %i(container_replicators
    #    container_services).each do |name|
    #   add_custom_attributes(name, %w(labels selectors))
    # end
    #
    # %i(container_builds
    #    container_build_pods
    #    container_routes
    #    container_templates).each do |name|
    #   add_custom_attributes(name, %w(labels))
    # end
  end

  # ContainerCondition is polymorphic child of ContainerNode & ContainerGroup.
  # @param manager [ExtManagementSystem]
  # @param association [Symbol]
  def add_container_conditions(manager, association)
    parent_collection = @collections[association]

    relation = manager.public_send(association)
    query = ContainerCondition.where(
      :container_entity_type => relation.model.base_class.name,
      :container_entity_id   => relation, # TODO(lsmola): JOIN will be much better, should be defined as relation
    )

    targeted_arel = lambda do |inventory_collection|
      # TODO(lsmola): if we use :association ^ instead of :arel, this can be autogenerated
      p_collection = inventory_collection.parent_inventory_collections.first
      rel = p_collection.db_collection_for_comparison_for(p_collection.targeted_scope.primary_references)

      ContainerCondition.where(
        :container_entity_type => rel.model.base_class.name,
        :container_entity_id   => rel,
      )
    end

    add_collection(container,
                   [:container_conditions_for, relation.model.base_class.name],
                   {},
                   {:auto_inventory_attributes => false}) do |builder|

      builder.add_properties(
        :model_class                  => ContainerCondition,
        :association                  => nil,
        :name                         => "container_conditions_for_#{association}".to_sym,
        :arel                         => query,
        :targeted_arel                => targeted_arel,
        :manager_ref                  => %i(container_entity name),
        :parent_inventory_collections => [parent_collection.name],
      )
    end
  end

  # CustomAttribute is polymorphic child of many models
  # @param parent [Symbol]
  # @param sections [Array<String>]
  def add_custom_attributes(parent, sections)
    parent_collection = @collections[parent]

    type = parent_collection.model_class.base_class.name
    relation = parent_collection.full_collection_for_comparison

    sections.each do |section|
      query = ::CustomAttribute.where(
        :resource_type => type,
        :resource_id   => relation, # TODO(lsmola): JOIN will be much better, should be defined as relation
        :section       => section.to_s
      )

      targeted_arel = lambda do |inventory_collection|
        # TODO(lsmola): if we use :association ^ instead of :arel, this can be autogenerated
        p_collection = inventory_collection.parent_inventory_collections.first
        rel = p_collection.db_collection_for_comparison_for(p_collection.targeted_scope.primary_references)

        CustomAttribute.where(
          :resource_type => rel.model.base_class.name,
          :resource_id   => rel,
          :section       => section.to_s
        )
      end

      add_collection(container, [:custom_attributes_for, type, section.to_s], {}, { :auto_inventory_attributes => false }) do |builder|
        builder.add_properties(
          :model_class                  => ::CustomAttribute,
          :association                  => nil,
          :name                         => "custom_attributes_for_#{parent_collection.name}_#{section}".to_sym,
          :arel                         => query,
          :targeted_arel                => targeted_arel,
          :manager_ref                  => %i(resource section name),
          :parent_inventory_collections => [parent_collection.name],
        )
      end
    end
  end

  protected

  def targeted?
    true
  end

  def strategy
    :local_db_find_missing_references
  end

  def saver_strategy
    :concurrent_safe_batch
  end

  def shared_options
    {
      :saver_strategy => saver_strategy,
      :strategy       => strategy,
      :targeted       => targeted?,
      :parent         => manager.presence
    }
  end
end
