# frozen_string_literal: true

#  Copyright (c) 2019-2023, Pfadibewegung Schweiz. This file is part of
#  hitobito and licensed under the Affero General Public License version 3
#  or later. See the COPYING file at the top-level directory or at
#  https://github.com/hitobito/hitobito.

class HelpTexts::Entry
  attr_reader :key, :action_names, :controller_name, :model_class

  def self.key(controller_name, model_class)
    [controller_name, model_class.to_s.underscore].compact.join("--")
  end

  def initialize(controller_name, model_class, existing = nil)
    @controller_name = controller_name
    @model_class = model_class
    @existing = existing || {}
    @key = self.class.key(controller_name, model_class)

    @action_names = []
  end

  def to_s
    model_class.model_name.human
  end

  def grouped
    %w[action field].collect do |kind|
      label = HelpText.human_attribute_name(kind.to_s, count: 2)
      list = labeled_list(kind)
      next if list.empty?

      OpenStruct.new(label: label, list: list)
    end.compact
  end

  def present?
    actions.present? || fields.present?
  end

  def translate(kind, name)
    format('%s "%s"', # rubocop:disable Style/FormatStringToken hard to name and little benfit
      HelpText.human_attribute_name(kind.to_s),
      send(:"translate_#{kind}", name))
  end

  def fields
    (
      (used_attributes + permitted_attributes) -
      (existing(:field) + blacklist)
    ).uniq
  end

  def actions(supported_actions = %w[index new edit show])
    (action_names & supported_actions) - existing(:action)
  end

  def labeled_list(kind)
    send(kind.to_s.pluralize).collect do |name, _|
      ["#{kind}.#{name}", send(:"translate_#{kind}", name)]
    end.compact.sort_by(&:second)
  end

  private

  def existing(key)
    @existing.fetch(key, []).collect(&:to_s)
  end

  def blacklist_key
    model_class.base_class.to_s.underscore.to_sym
  end

  def blacklist
    Settings.help_text_blacklist.to_h.fetch(blacklist_key, []).map(&:to_s)
  end

  def used_attributes
    (model_class.try(:used_attributes) || []).map(&:to_s)
  end

  def permitted_attributes
    Array.wrap(controller_class.try(:permitted_attrs)).collect do |key|
      key.is_a?(Hash) ? key.keys.first : key
    end.map(&:to_s)
  end

  def translate_action(action, mapping = {index: :list, new: :add})
    I18n.t("global.link.#{mapping.fetch(action.to_sym, action)}")
  end

  def translate_field(field)
    model_class.human_attribute_name(field)
  end

  def controller_class
    @controller_class ||= "#{@controller_name}_controller".classify.constantize
  end
end
