/**
 * Cyber-Assistant — Entity Manager (multi-entités, mode serveur)
 * ---------------------------------------------------------------------------
 * État et logique client de la feature multi-entités. Le SERVEUR fait autorité
 * et applique l'isolation ; ce module ne fait qu'ADAPTER le client universel à
 * ce que le serveur renvoie (bloc `multiEntity` de /me et /login).
 *
 * GARANTIE DE NON-RÉGRESSION : quand le mode n'est pas actif (installation
 * mono-organisation, ou feature désactivée), TOUTES les fonctions réseau sont
 * des no-op — mêmes URLs, mêmes corps de requête qu'avant. Un install serveur
 * sans multi-entités se comporte à l'identique.
 *
 * Inerte en mode local (file://) via un stub, comme auth-manager (ADR-002).
 * ES5 strict (var, pas d'arrow functions).
 */
(function() {
  'use strict';

  // État (volatile, jamais persisté — le scope initial est toujours l'entité
  // principale après login/reload : décision PO, anti-confusion §11.3).
  var _multiEntity = null;   // bloc renvoyé par le serveur, ou null si off
  var _activeScope = null;   // id de sous-entité ciblée par un compte principal ; null = principal
  var _groupView = null;     // sidecar _csiGroupView (Lot 3b) — données du groupe en LECTURE,
                             // capturé au pull, jamais dans appData, jamais persisté

  function _enabled() { return !!(_multiEntity && _multiEntity.enabled); }
  function _entityIds() { return (_multiEntity && _multiEntity.entityIds) || []; }
  // === CSI-ME === (audit co-édition 2026-08-05, MAJEUR) Périmètre par défaut d'un compte
  // multi-appartenance : la PREMIÈRE entité ACTIVE, pas la première de la liste brute.
  // `entityIds` inclut les entités ARCHIVÉES alors que `entities` ne liste que les actives ;
  // le serveur, lui, replie sur la première ACTIVE en l'absence de `entity=`. Si la 1re
  // entité du compte était archivée, l'écho pointait donc l'archivée et le serveur l'entité
  // active → 409 ENTITY_CONTEXT_CHANGED PERMANENT, le client rechargeant en boucle sans issue.
  // Repli sur la liste brute si aucune n'est active : le compte est de toute façon verrouillé
  // (fail-closed volontaire) et l'écho reste cohérent avec ce que le serveur refusera.
  function _defaultSubEntityId() {
    var ids = _entityIds();
    var actives = (_multiEntity && _multiEntity.entities) || [];
    for (var i = 0; i < ids.length; i++) {
      for (var j = 0; j < actives.length; j++) {
        if (actives[j] && actives[j].id === ids[i]) return ids[i];
      }
    }
    return ids[0];
  }
  function _isSubEntityUser() { return _enabled() && _entityIds().length > 0; }
  function _isGroupUser() { return _enabled() && _entityIds().length === 0; }

  var EntityManager = {
    /**
     * Ingère la réponse d'auth (/me, /login). Réinitialise le périmètre actif à
     * l'entité principale (jamais de « dernier périmètre visité » persistant).
     */
    ingest: function(data) {
      _multiEntity = (data && data.multiEntity) ? data.multiEntity : null;
      _activeScope = null;
      // Au reload avec session, /me résout APRÈS le rendu initial de la nav :
      // applyNis2Referential (porteur du masquage/bandeau) a déjà tourné à vide.
      // On rejoue la vue une fois l'état ingéré (no-op hors mode / avant DOM).
      if (window.CSI_EntityUI && window.CSI_EntityUI.applySubEntityView) {
        setTimeout(function() { try { window.CSI_EntityUI.applySubEntityView(); } catch (e) {} }, 0);
      }
    },

    isMultiEntity: function() { return _enabled(); },
    isSubEntityUser: function() { return _isSubEntityUser(); },
    isGroupUser: function() { return _isGroupUser(); },
    info: function() { return _multiEntity; },

    /** Liste des sous-entités pour le sélecteur (comptes principaux). */
    entities: function() { return (_multiEntity && _multiEntity.entities) || []; },
    canEditSubEntities: function() { return !!(_multiEntity && _multiEntity.canEditSubEntities); },

    /**
     * Droit effectif sur une section : compte de sous-entité → sa matrice ;
     * compte principal → 'write' (édite tout). Hors mode → 'write' (inchangé).
     */
    sectionRight: function(tabId) {
      if (!_enabled()) return 'write';
      if (_isSubEntityUser()) {
        // Multi-appartenance (Lot 3c) : droits de l'entité ACTIVE si le serveur les
        // fournit (sectionsByEntity) ; sinon matrice historique (sections = ids[0]).
        var active = _activeScope || _entityIds()[0];
        var byEnt = _multiEntity.sectionsByEntity;
        var s = (byEnt && byEnt[active]) ? byEnt[active] : (_multiEntity.sections || {});
        return Object.prototype.hasOwnProperty.call(s, tabId) ? s[tabId] : 'none';
      }
      return 'write';
    },
    canRead: function(tabId) { return this.sectionRight(tabId) !== 'none'; },
    canWrite: function(tabId) { return this.sectionRight(tabId) === 'write'; },

    /** Sections que le serveur laisse voir de l'entité principale (sidecar). */
    groupViewSections: function() { return (_multiEntity && _multiEntity.groupView) || []; },

    /** (Lot 3b) Sidecar _csiGroupView : {sectionId: [items]} — lecture seule, volatile. */
    ingestGroupView: function(gv) { _groupView = (gv && typeof gv === 'object') ? gv : null; },
    groupViewData: function() { return _groupView || {}; },

    /**
     * Périmètre actif : compte principal → id de sous-entité ciblée (null = principal) ;
     * compte de sous-entité multi-appartenance (Lot 3c) → id de SON entité active
     * (null = sa première entité, comportement historique).
     */
    activeScope: function() { return _enabled() ? _activeScope : null; },
    setActiveScope: function(entityId) {
      if (_isGroupUser()) {
        _activeScope = entityId ? String(entityId) : null;
        return true;
      }
      if (_isSubEntityUser()) {
        // Multi-appartenance : bascule UNIQUEMENT parmi ses propres entités (le
        // serveur re-valide de toute façon — entCtx force ids[0] hors liste).
        var ids = _entityIds();
        var target = entityId ? String(entityId) : ids[0];
        if (ids.indexOf(target) < 0) return false;
        _activeScope = (target === ids[0]) ? null : target; // null = entité par défaut
        return true;
      }
      return false;
    },

    /**
     * Valeur du paramètre ?entity= à ajouter aux requêtes, ou null si aucune.
     * - compte de sous-entité : null par défaut (le serveur dérive du JWT) ; l'id
     *   ciblé si multi-appartenance avec bascule active (validé serveur ∈ entityIds).
     * - compte principal avec périmètre actif : l'id ciblé.
     * - hors mode / périmètre par défaut : null → URL inchangée.
     */
    entityParam: function() {
      if (!_enabled()) return null;
      if (_activeScope) return _activeScope;
      return null;
    },

    /** Écho d'identité de partition (V16) attendu par le serveur en écriture. */
    echoId: function() {
      if (!_enabled()) return null;
      if (_isSubEntityUser()) return _activeScope || _defaultSubEntityId();
      if (_activeScope) return _activeScope;
      return 'group';
    },

    /** Ajoute ?entity=/&entity= à une URL si un périmètre est ciblé. No-op sinon. */
    appendEntityParam: function(url) {
      var p = this.entityParam();
      if (!p) return url;
      return url + (url.indexOf('?') === -1 ? '?' : '&') + 'entity=' + encodeURIComponent(p);
    },

    /**
     * Champs à fusionner dans le corps d'un POST d'écriture (data-push/import).
     * En mode actif : {entityEcho, entity?}. Hors mode : {} (corps inchangé).
     */
    pushBodyExtra: function() {
      if (!_enabled()) return {};
      var extra = { entityEcho: this.echoId() };
      var p = this.entityParam();
      if (p) extra.entity = p;
      return extra;
    },

    /** Réinitialisation (logout). */
    reset: function() { _multiEntity = null; _activeScope = null; _groupView = null; }
  };

  // Inerte en mode local (file://) — stub neutre (ADR-002).
  if (window.CSI_LicenseManager && !window.CSI_LicenseManager.isServerMode() &&
      (window.CSI_LicenseManager.isDetected() || window.location.protocol === 'file:')) {
    window.CSI_EntityManager = {
      ingest: function() {}, isMultiEntity: function() { return false; },
      isSubEntityUser: function() { return false; }, isGroupUser: function() { return false; },
      info: function() { return null; }, entities: function() { return []; },
      canEditSubEntities: function() { return false; },
      sectionRight: function() { return 'write'; },
      canRead: function() { return true; }, canWrite: function() { return true; },
      groupViewSections: function() { return []; },
      ingestGroupView: function() {}, groupViewData: function() { return {}; },
      activeScope: function() { return null; }, setActiveScope: function() { return false; },
      entityParam: function() { return null; }, echoId: function() { return null; },
      appendEntityParam: function(url) { return url; }, pushBodyExtra: function() { return {}; },
      reset: function() {}
    };
    void 0;
    return;
  }

  if (window.CSI && window.CSI.register) {
    window.CSI.register('entity-manager', { exports: { CSI_EntityManager: EntityManager } });
  }
  window.CSI_EntityManager = EntityManager;
  if (window._csiPendingEntityAuthData) {
    EntityManager.ingest(window._csiPendingEntityAuthData);
    try { delete window._csiPendingEntityAuthData; } catch (e) { window._csiPendingEntityAuthData = null; }
  }
  void 0;
})();
