# frozen_string_literal: true

module ActiveModelSerializers
  module LookupChain
    # Standard appending of Serializer to the resource name.
    #
    # Example:
    #   Author => AuthorSerializer
    BY_RESOURCE = lambda do |resource_class, _serializer_class, _namespace|
      serializer_from(resource_class)
    end

    # Uses the namespace of the resource to find the serializer
    #
    # Example:
    #  British::Author => British::AuthorSerializer
    BY_RESOURCE_NAMESPACE = lambda do |resource_class, _serializer_class, _namespace|
      resource_namespace = namespace_for(resource_class)
      serializer_name = serializer_from(resource_class)

      "#{resource_namespace}::#{serializer_name}"
    end

    # Uses the controller namespace of the resource to find the serializer
    #
    # Example:
    #  Api::V3::AuthorsController => Api::V3::AuthorSerializer
    BY_NAMESPACE = lambda do |resource_class, _serializer_class, namespace|
      resource_name = resource_class_name(resource_class)
      namespace ? "#{namespace}::#{resource_name}Serializer" : nil
    end

    # Allows for serializers to be defined in parent serializers
    # - useful if a relationship only needs a different set of attributes
    #   than if it were rendered independently.
    #
    # Example:
    #   class BlogSerializer < ActiveModel::Serializer
    #     class AuthorSerialier < ActiveModel::Serializer
    #     ...
    #     end
    #
    #     belongs_to :author
    #     ...
    #   end
    #
    #  The belongs_to relationship would be rendered with
    #    BlogSerializer::AuthorSerialier
    BY_PARENT_SERIALIZER = lambda do |resource_class, serializer_class, _namespace|
      return if serializer_class == ActiveModel::Serializer

      serializer_name = serializer_from(resource_class)
      "#{serializer_class}::#{serializer_name}"
    end

    DEFAULT = [
      BY_PARENT_SERIALIZER,
      BY_NAMESPACE,
      BY_RESOURCE_NAMESPACE,
      BY_RESOURCE
    ].freeze

    module_function

    def namespace_for(klass)
      klass.name.deconstantize
    end

    def resource_class_name(klass)
      klass.name.demodulize
    end

    def serializer_from_resource_name(name)
      "#{name}Serializer"
    end

    def serializer_from(klass)
      name = resource_class_name(klass)
      serializer_from_resource_name(name)
    end
  end
end
