class Avo::Resources::ResourceManager

def build

def build
  instance = new
  instance.check_bad_resources
  instance
end

def check_bad_resources

def check_bad_resources
  resources.each do |resource|
    has_model = resource.model_class.present?
    unless has_model
      possible_model = resource.to_s.gsub "Avo::Resources::", ""
      possible_model = possible_model.gsub "Resource", ""
      Avo.error_manager.add({
        url: "https://docs.avohq.io/3.0/resources.html#self_model_class",
        target: "_blank",
        message: "#{resource} does not have a valid model assigned. It failed to find the #{possible_model} model. \n\r Please create that model or assign one using self.model_class = YOUR_MODEL"
      })
    end
  end
end

def fetch_resources

]
"FishResource",
"UserResource",
config.resources = [
To enable this feature add a `resources` array config in your Avo initializer.

and they are not available.
At that boot time some migration might have not been run yet, but Rails tries to access them through model associations,
The scenario that comes up most often is when Rails boots, the routes are being computed which eager loads the resource files.
other classes in a chain reaction.
Ex: AdminResource may use self.model_class = User. That will trigger Ruby to load the User class and itself load
those Resource classes and their methods may trigger loading other classes. And that may disrupt Rails booting process.
We have this option to load the resources because when they are loaded automatically through eager loading,
2. Manually, declared by the user.

This is the simple way to get started.
We automatically eager load the resources directory and fetch the descendants from the scanned files.
1. Through eager loading.

We have two ways of doing that.
Fetches the resources available to the application.
def fetch_resources
  if Avo.configuration.resources.present?
    load_configured_resources
  else
    load_resources_namespace
  end
  # All descendants from Avo::Resources::Base except the internal abstract ones
  Base.descendants.reject { _1.is_abstract? }
end

def get_available_resources(user = nil)

def get_available_resources(user = nil)
  valid_resources
    .select do |resource|
      resource.authorization.class.authorize(
        user,
        resource.model_class,
        Avo.configuration.authorization_methods.stringify_keys["index"],
        policy_class: resource.authorization_policy,
        raise_exception: false
      )
    end
    .sort_by { |r| r.name }
end

def get_mapping_for_model(klass)

def get_mapping_for_model(klass)
  (Avo.configuration.model_resource_mapping || {}).stringify_keys.transform_values(&:to_s)[klass.to_s]
end

def get_model_class_by_name(name)

get_model_class_by_name('user') => User

Returns the Rails model class by singular snake_cased name
def get_model_class_by_name(name)
  name.to_s.camelize.singularize
end

def get_resource(resource)

get_resource_by_name('User') => instance of Avo::Resources::User

Returns the Avo resource by camelized name
def get_resource(resource)
  resource = "Avo::Resources::#{resource}" unless resource.to_s.starts_with?("Avo::Resources::")
  resources.find do |available_resource|
    resource.to_s == available_resource.to_s
  end
end

def get_resource_by_controller_name(name)

get_resource_by_controller_name('users') => instance of Avo::Resources::User
get_resource_by_controller_name('delayed_backend_active_record_jobs') => instance of Avo::Resources::DelayedJob

Returns the Avo resource by singular snake_cased name
def get_resource_by_controller_name(name)
  valid_resources
    .find do |resource|
      resource.model_class.to_s.pluralize.underscore.tr("/", "_") == name.to_s
    end
end

def get_resource_by_model_class(klass)

def get_resource_by_model_class(klass)
  # Fetch the mappings imposed by the user.
  # If they are present, use those ones.
  mapping = get_mapping_for_model klass
  return get_resource(mapping) if mapping.present?
  valid_resources
    .find do |resource|
      resource.model_class.model_name.name == klass.to_s
    end
end

def get_resource_by_name(name)

get_resource_by_name('user') => instance of Avo::Resources::User

Returns the Avo resource by singular snake_cased name
def get_resource_by_name(name)
  get_resource name.singularize.camelize
end

def get_resource_by_plural_name(name)

get_resource_by_name('z posts') => instance of Avo::Resources::ZPost

Returns the Avo resource by singular snake_cased name
def get_resource_by_plural_name(name)
  resources.find do |resource|
    resource.plural_name == name
  end
end

def guess_resource(name)

Returns the Avo resource by some name
def guess_resource(name)
  get_resource_by_name(name.to_s) || get_resource_by_model_class(name)
end

def initialize

def initialize
  @resources = self.class.fetch_resources
end

def load_configured_resources

def load_configured_resources
  raise "Resources configuration must be an array" unless Avo.configuration.resources.is_a? Array
  Avo.configuration.resources.each do |resource|
    resource.to_s.safe_constantize
  end
end

def load_resources_namespace

def load_resources_namespace
  Rails.autoloaders.main.eager_load_namespace(Avo::Resources)
end

def resources_for_navigation(user = nil)

def resources_for_navigation(user = nil)
  get_available_resources(user)
    .select do |resource|
      resource.visible_on_sidebar
    end
end

def valid_resources

Filters out the resources that are missing the model_class
def valid_resources
  resources.select { |resource| resource.model_class.present? }.sort_by(&:name)
end