module GG_CabinetTools
  Dir.mkdir(CORE_DIR) unless File.directory?(CORE_DIR)

  # Every core file is parsed exactly ONCE per session: load_core_once (defined
  # by the top-level gg_cabinet_tools.rb, which always runs before this file)
  # keeps a registry of what it has already loaded. That covers the foundation
  # the top-level loader brought in before `main` (rgloader, util, locale, api —
  # the calls below are then free no-ops that still document the load order),
  # and a disable/re-enable in the Extension Manager, which re-runs main.rb.
  # The calls are kept explicit because order matters: tool_commands and
  # bug_snag must exist before the glob loads the tools that use them.

  # Normally already done by the top-level loader (so this is a no-op); kept as
  # a fallback because nothing encoded can load without the RubyEncoder loader.
  load_core_once(File.join(CORE_DIR, "rgloader", "loader.rb"))

  load_core = ->(name) {
    rbe = File.join(CORE_DIR, "#{name}.rbe")
    rb  = File.join(CORE_DIR, "#{name}.rb")
    load_core_once(File.exist?(rbe) ? rbe : rb)
  }

  load_core.call("util")
  load_core.call("locale")
  load_core.call("tool_commands")
  load_core.call("api")
  load_core.call("bug_snag") # crash catcher — must exist before the guards install

  load_core.call("warehouse_store")

  load_core.call("solid_operations")
  load_core.call("abf_lib")

  # nesting_editor_* siblings are loaded by nesting_editor_tool.rb itself
  # (see its prelude), so the glob below must skip them to avoid a double load.
  core_skip_bases = (%w[util locale tool_commands api bug_snag warehouse_store update_launcher checksums manifest item_upload item_download watcher warehouse_cable solid_operations unfold_settings_normalize tenon_helper_tool] +
    %w[nesting_editor_logic nesting_editor_logic_collision nesting_editor_logic_outer_cut
       nesting_editor_logic_reorder nesting_editor_tool_cut_modes nesting_editor_tool_drag
       nesting_editor_tool_edit_edges nesting_editor_tool_hud nesting_editor_tool_interact
       nesting_editor_tool_move nesting_editor_tool_pack nesting_editor_tool_sheet_ui]).freeze
  core_skip = core_skip_bases.flat_map { |b| ["#{b}.rb", "#{b}.rbe"] }.freeze
  Dir.glob(File.join(CORE_DIR, "**", "*.{rb,rbe}")).each do |f|
    # The native RubyEncoder loader is bootstrapped by the top-level loader only.
    next if f.tr("\\", "/").include?("/rgloader/")
    next if core_skip.include?(File.basename(f))

    load_core_once(f)
  end
  # Every plugin tool is now loaded — wrap their Tool-protocol callbacks so a
  # raise is reported to Bugsnag and swallowed instead of crashing SketchUp.
  GG_CabinetTools::BugSnag.install_tool_guards! if defined?(GG_CabinetTools::BugSnag)

  # The actual toolbar/menu wiring — including the sign-in/admin license gate
  # around every tool command — lives in core/toolbar_builder.rb, loaded by the
  # loop above. main.rb can never be RubyEncoder-protected itself (SketchUp's
  # SketchupExtension needs a literal main.rb on disk at the registered path),
  # so it stays a thin, uninteresting stub instead of holding anything worth
  # patching to bypass the license check.
  unless file_loaded?(__FILE__)
    GG_CabinetTools.install_toolbar!
    file_loaded(__FILE__)
  end
end
