# frozen_string_literal: true
module ActiveAdmin
  # This is a container for resources, which acts much like a Hash.
  # It's assumed that an added resource responds to `resource_name`.
  class ResourceCollection
    include Enumerable
    extend Forwardable
    def_delegators :@collection, :empty?, :has_key?, :keys, :values, :size

    def initialize
      @collection = {}
    end

    def add(resource)
      if match = @collection[resource.resource_name]
        raise_if_mismatched! match, resource
        match
      else
        @collection[resource.resource_name] = resource
      end
    end

    # Changes `each` to pass in the value, instead of both the key and value.
    def each(&block)
      values.each(&block)
    end

    def [](obj)
      @collection[obj] || find_resource(obj)
    end

    private

    # Finds a resource based on the resource name, resource class, or base class.
    def find_resource(obj)
      resources.detect do |r|
        r.resource_name.to_s == obj.to_s
      end || resources.detect do |r|
        r.resource_class.to_s == obj.to_s
      end ||
      if obj.respond_to? :base_class
        resources.detect { |r| r.resource_class.to_s == obj.base_class.to_s }
      end
    end

    def resources
      select { |r| r.class <= Resource } # can otherwise be a Page
    end

    def raise_if_mismatched!(existing, given)
      if existing.class != given.class
        raise IncorrectClass.new existing, given
      elsif given.class <= Resource && existing.resource_class != given.resource_class
        raise ConfigMismatch.new existing, given
      end
    end

    class IncorrectClass < StandardError
      def initialize(existing, given)
        super "You're trying to register #{given.resource_name} which is a #{given.class}, " +
              "but #{existing.resource_name}, a #{existing.class} has already claimed that name."
      end
    end

    class ConfigMismatch < StandardError
      def initialize(existing, given)
        super "You're trying to register #{given.resource_class} as #{given.resource_name}, " +
              "but the existing #{existing.class} config was built for #{existing.resource_class}!"
      end
    end

  end
end
