class Avo::BaseResource

def action(action_class)

def action(action_class)
  self.actions_loader ||= Avo::Loaders::Loader.new
  self.actions_loader.use action_class
end

def attached_file_fields

def attached_file_fields
  get_field_definitions.select do |field|
    [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
  end
end

def authorization

def authorization
  Avo::Services::AuthorizationService.new Avo::App.current_user
end

def authorization

def authorization
  Avo::Services::AuthorizationService.new(user, model || model_class)
end

def available_view_types

def available_view_types
  view_types = [:table]
  view_types << :grid if get_grid_fields.present?
  view_types
end

def avatar

def avatar
  return avatar_field.to_image if avatar_field.respond_to? :to_image
  return avatar_field.value.variant(resize_to_limit: [480, 480]) if avatar_field.type == "file"
  avatar_field.value
rescue
  nil
end

def avatar_field

def avatar_field
  get_field_definitions.find do |field|
    field.as_avatar.present?
  end
rescue
  nil
end

def avatar_type

def avatar_type
  avatar_field.as_avatar
rescue
  nil
end

def avo_path

def avo_path
  "#{Avo::App.root_path}/resources/#{model_class.model_name.route_key}/#{model.id}"
end

def cache_hash(parent_model)

def cache_hash(parent_model)
  if parent_model.present?
    [model, file_hash, parent_model]
  else
    [model, file_hash]
  end
end

def context

def context
  self.class.context
end

def default_panel_name

def default_panel_name
  return @params[:related_name].capitalize if @params.present? && @params[:related_name].present?
  case @view
  when :show
    I18n.t("avo.resource_details", item: name.downcase, title: model_title).upcase_first
  when :edit
    I18n.t("avo.update_item", item: name.downcase, title: model_title).upcase_first
  when :new
    I18n.t("avo.create_new_item", item: name.downcase).upcase_first
  end
end

def description

def description
  description_field.value
rescue
  nil
end

def description_field

def description_field
  get_field_definitions.find do |field|
    field.as_description.present?
  end
rescue
  nil
end

def file_hash

def file_hash
  content_to_be_hashed = ""
  # resource file hash
  resource_path = Rails.root.join("app", "avo", "resources", "#{self.class.name.underscore}.rb").to_s
  if File.file? resource_path
    content_to_be_hashed += File.read(resource_path)
  end
  # policy file hash
  policy_path = Rails.root.join("app", "policies", "#{self.class.name.underscore.gsub("_resource", "")}_policy.rb").to_s
  if File.file? policy_path
    content_to_be_hashed += File.read(policy_path)
  end
  Digest::MD5.hexdigest(content_to_be_hashed)
end

def fill_model(model, params)

def fill_model(model, params)
  # Map the received params to their actual fields
  fields_by_database_id = get_field_definitions
    .reject do |field|
      field.computed
    end
    .map do |field|
      [field.database_id(model).to_s, field]
    end
    .to_h
  params.each do |key, value|
    field = fields_by_database_id[key]
    next unless field.present?
    model = field.fill_field model, key, value, params
  end
  model
end

def filter(filter_class)

def filter(filter_class)
  self.filters_loader ||= Avo::Loaders::Loader.new
  self.filters_loader.use filter_class
end

def find_scope

This resolves the scope when finding records (not "where" queries)
def find_scope
  final_scope = resolve_find_scope.present? ? resolve_find_scope.call(model_class: model_class) : model_class
  authorization.apply_policy final_scope
end

def get_actions

def get_actions
  return [] if self.class.actions_loader.blank?
  self.class.actions_loader.bag
end

def get_field_definitions

def get_field_definitions
  return [] if self.class.fields.blank?
  fields = self.class.fields.map do |field|
    field.hydrate(resource: self, panel_name: default_panel_name, user: user)
  end
  if Avo::App.license.lacks_with_trial(:custom_fields)
    fields = fields.reject do |field|
      field.custom?
    end
  end
  fields
end

def get_fields(panel: nil, reflection: nil)

def get_fields(panel: nil, reflection: nil)
  fields = get_field_definitions
    .select do |field|
      field.send("show_on_#{@view}")
    end
    .select do |field|
      field.visible?
    end
    .select do |field|
      # Strip out the reflection field in index queries with a parent association.
      if reflection.present? &&
          reflection.options.present? &&
          field.respond_to?(:polymorphic_as) &&
          field.polymorphic_as.to_s == reflection.options[:as].to_s
        next
      end
      if field.respond_to?(:foreign_key) &&
          reflection.present? &&
          reflection.respond_to?(:foreign_key) &&
          reflection.foreign_key != field.foreign_key
        next
      end
      true
    end
  if panel.present?
    fields = fields.select do |field|
      field.panel_name == panel
    end
  end
  hydrate_fields(model: @model, view: @view)
  fields
end

def get_filters

def get_filters
  return [] if self.class.filters_loader.blank?
  self.class.filters_loader.bag
end

def get_grid_fields

def get_grid_fields
  return if self.class.grid_loader.blank?
  self.class.grid_loader.hydrate(model: @model, view: @view, resource: self)
end

def grid(&block)

def grid(&block)
  grid_collector = GridCollector.new
  grid_collector.instance_eval(&block)
  self.grid_loader = grid_collector
end

def hydrate(model: nil, view: nil, user: nil, params: nil)

def hydrate(model: nil, view: nil, user: nil, params: nil)
  @view = view if view.present?
  @user = user if user.present?
  @params = params if params.present?
  if model.present?
    @model = model
    hydrate_model_with_default_values if @view == :new
  end
  self
end

def hydrate_fields(model: nil, view: nil)

def hydrate_fields(model: nil, view: nil)
  fields.map do |field|
    field.hydrate(model: @model, view: @view, resource: self)
  end
  self
end

def hydrate_model_with_default_values

We will not overwrite any attributes that come pre-filled in the model.
def hydrate_model_with_default_values
  default_values = get_fields
    .select do |field|
      !field.computed
    end
    .map do |field|
      id = field.id
      value = field.value
      if field.type == "belongs_to"
        id = field.foreign_key.to_sym
        reflection = @model._reflections[@params[:via_relation]]
        if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params["via_relation_class"])
          value = @params["via_relation_class"].safe_constantize.find(@params[:via_resource_id])
        elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
          value = @params[:via_resource_id]
        end
      end
      [id, value]
    end
    .to_h
    .select do |id, value|
      value.present?
    end
  default_values.each do |id, value|
    if @model.send(id).nil?
      @model.send("#{id}=", value)
    end
  end
end

def initialize

def initialize
  self.class.model_class = model_class
end

def label

def label
  label_field.value || model_title
rescue
  model_title
end

def label_field

def label_field
  get_field_definitions.find do |field|
    field.as_label.present?
  end
rescue
  nil
end

def model_class

def model_class
  return self.class.model_class if self.class.model_class.present?
  return @model.class if @model.present?
  self.class.name.demodulize.chomp("Resource").safe_constantize
end

def model_title

def model_title
  return @model.send title if @model.present?
  name
end

def name

def name
  return @name if @name.present?
  return I18n.t(@translation_key, count: 1).capitalize if @translation_key
  self.class.name.demodulize.chomp("Resource").titlecase
end

def panels

def panels
  [
    {
      name: default_panel_name,
      type: :fields,
      in_panel: true
    }
  ]
end

def plural_name

def plural_name
  return I18n.t(@translation_key, count: 2).capitalize if @translation_key
  name.pluralize
end

def query_scope

This resolves the scope when doing "where" queries (not find queries)
def query_scope
  final_scope = resolve_query_scope.present? ? resolve_query_scope.call(model_class: model_class) : model_class
  authorization.apply_policy final_scope
end

def route_key

def route_key
  model_class.model_name.route_key
end

def scope

This should be removed and passed to the search block
This is the search_query scope
def scope
  self.query_scope
end

def singular_name

def singular_name
  name
end

def underscore_name

def underscore_name
  return @name if @name.present?
  self.class.name.demodulize.underscore
end