# This "model" is not backed by the database. Its main purpose is to
# setup and provide methods to interact with the admin sidebar and tabbed menu
class AdminMenu
  # On second level navigation with more children, we reference the default tabs controller. i.e look at developer_tools
  # rubocop:disable Metrics/BlockLength
  ITEMS = Menu.define do
    scope :member_manager, "group-2-line", [
      item(name: "members", controller: "users"),
      item(name: "invited members", controller: "invitations"),
      item(name: "gdpr actions", controller: "gdpr_delete_requests"),
      item(name: "bulk assign role", controller: "bulk_assign_role"),
    ]

    scope :content_manager, "dashboard-line", [
      item(name: "spaces", controller: "spaces"),
      item(name: "posts", controller: "articles"),
      item(name: "comments", controller: "comments"),
      item(name: "badges", children: [
             item(name: "library", controller: "badges"),
             item(name: "achievements", controller: "badge_achievements"),
           ]),
      item(name: "organizations"),
      item(name: "podcasts"),
      item(name: "tags"),
      item(name: "emails"),
    ]

    scope :customization, "tools-line", [
      item(name: "config"),
      item(name: "billboards"),
      item(name: "navigation links"),
      item(name: "pages"),
      item(name: "profile fields"),
      item(name: "subforems"),
    ]

    scope :admin_team, "user-line", [
      item(name: "admin team", controller: "permissions", parent: "permissions"),
    ]

    scope :moderation, "mod", [
      item(name: "reports"),
      item(name: "mods"),
      item(name: "moderator actions", controller: "moderator_actions"),
      item(name: "privileged reactions"),
      item(name: "blocked email domains", controller: "blocked_email_domains"),
    ]

    scope :advanced, "flashlight-line", [
      item(name: "broadcasts"),
      item(name: "response templates"),
      item(name: "developer tools", controller: "tools", children: [
             item(name: "tools"),
             item(name: "data update scripts", visible: -> { FeatureFlag.enabled?(:data_update_scripts) }),
             item(name: "extensions", controller: "extensions"),
           ]),
    ]

    scope :apps, "palette-line", [
      item(name: "consumer apps", controller: "consumer_apps"),
      item(name: "welcome"),
    ]
  end.freeze
  # rubocop:enable Metrics/BlockLength

  def self.navigation_items
    ITEMS
  end

  # Return the Menu item that corresponds to the nav_item within the given named scope.
  #
  # @param scope_name [String] a slug from the request.path, which, by convention maps to the scope
  #        declarations in {ITEMS}.
  # @param nav_item [String] a slug from the request.path, which, by convention maps to the item
  #        declarations that are one level below the scope declarations of {ITEMS}.
  #
  # @return [NilClass] when we don't have a menu representation of the nav_item
  # @return [Menu::Item] the representation of the nav_item
  #
  # @todo This method returns the nav_item, but we really only operate on that item's children.
  #       Consider replacing with a method that is "children of nav_item within scope".
  #
  # @see AdminMenu.nested_menu_items_from_request
  # @see AdminMenu::ITEMS
  def self.nested_menu_items(scope_name, nav_item)
    children = navigation_items[scope_name.to_sym]&.children
    return unless children

    children.each do |items|
      return items if items.controller == nav_item

      next unless items.children&.any?

      items.children.each do |child|
        # NOTE: [@jeremyf] trying to puzzle this one out.  My read is that if the "grandchild" of the
        # scope matches the controller, return the parent node (e.g. the item).
        return items if child.controller == nav_item
      end
    end

    # Because we're using each loops, with short-circuiting returns, we need to make sure we don't
    # return the results of `items[:children].each`, which will be `items[:children]`.
    nil
  end

  # @param request [#path] the request object (which must respond to `#path`)
  # @return [NilClass] when we don't have a menu representation of the nav_item
  # @return [MenuItem] the representation of the nav_item
  #
  # @see {.nested_menu_items} for implementation details
  #
  # @note This method assumes that the last two slugs of the request's path are the relevant
  #       information for determining which menu item to return.  In other words, strongly consider
  #       the impact of having admin routes whose paths are comprised of more than 3 slugs (.e.g. we
  #       assume /admin/:scope_name/:nav_item but be wary of /admin/something/:scope_name/:nav_item
  #       or /admin/:scope_name/something/:nav_item).
  def self.nested_menu_items_from_request(request)
    scope, nav_item = request.path.split("/").last(2)
    nested_menu_items(scope, nav_item)
  end
end
