// kernel/services.js — the dependency-injection container (window.LP.services).
//
// An ADDITIVE, typed, lazy view onto the existing cross-cutting singletons. It
// constructs NOTHING: every member is a getter that returns the live global, so
// there is no double-instantiation and the globals stay authoritative. Feature
// modules receive it as ctx.services (kernel/lifecycle.js) and use it instead of
// reaching for window.* directly — the seam the rest of the de-globalisation
// builds on. Access only inside mount()/unmount() (post-boot), never at a
// feature's module top level, so the lazy getters always resolve.
//
// NOTE: page-owned controllers (appsManager, appTabbedManager, configManager,
// backupPage, systemPage, …) are NOT services — they belong to their feature —
// so they are deliberately absent here. Slot names + globals were verified
// against the real code (the design doc's §4 list had several wrong names).
(function () {
  const LP = (window.LP = window.LP || {});

  LP.services = {
    // Task system — the locked-down mutation front door + the live status bus.
    tasks: {
      get bus()     { return window.taskEventBus; },   // the single SSE EventSource
      get refresh() { return window.taskRefresh; },    // refresh coordinator (register/unregister)
      // .routeAction(action, params) is the mutation path (mutations-via-tasks).
      // Can be null if TasksManager construction failed — callers keep `?.`.
      get route()   { return window.tasksManager ? window.tasksManager.router : null; },
    },
    get live()   { return window.LiveSystem; },         // 1 Hz system SSE: subscribe/pause/resume
    get auth()   { return window.authManager; },        // logout()/interceptFetch()/isAuthenticated
    // DataLoader is a bare classic-script class (not a window property), so fall
    // back to the lexical binding.
    get data()   { return (typeof DataLoader !== 'undefined') ? DataLoader : (window.DataLoader || null); },
    // Reuse the codebase's own get-or-create net; never `new NotificationSystem()`
    // here (would append a second toast container).
    get notify() { return window.notificationSystem || (window.ensureNotificationSystem && window.ensureNotificationSystem()); },
    get theme()  { return window.ThemeRegistry; },      // theme discovery/list
    // The eo-modal toolkit is six free functions, not one object — group them.
    get modal()  {
      return {
        open: window.openEoModal,
        section: window.eoSection, badgeRow: window.eoBadgeRow,
        urlList: window.eoUrlList, credList: window.eoCredList, empty: window.eoEmpty,
      };
    },
    // The router surface is split: the spaClean instance (runtime methods, bound
    // to preserve `this`) + the standalone URL helpers. Return a fresh delegating
    // object — never Object.assign onto the live singleton.
    get router() {
      const spa = window.spaClean;
      return {
        navigate: (...a) => spa && spa.navigate(...a),
        loadScript: (s) => spa && spa.loadScript(s),
        fetchContent: (u) => spa && spa.fetchContent(u),
        loadContent: (h, t) => spa && spa.loadContent(h, t),
        navigateToRoute: window.navigateToRoute,
        appPath: window.appPath,
        appPartsFromPath: window.appPartsFromPath,
        adminPath: window.adminPath,
        adminCategoryFromPath: window.adminCategoryFromPath,
      };
    },
  };
})();
