/**
 * Cyber-Assistant - Module de stockage centralisé
 *
 * Centralise toutes les clés localStorage/sessionStorage et fournit
 * une API unifiée pour l'accès aux données de configuration.
 *
 * Ce module élimine la duplication de code entre save-manager.js,
 * server-sync.js et server-setup.js.
 */
(function() {
  'use strict';

  // ============================================================
  // Constantes - Clés de stockage centralisées
  // ============================================================

  var KEYS = {
    // Données principales
    DATA: 'smsi_data',
    LAST_SAVE: 'smsi_last_save',
    LAST_SERVER_PULL: 'smsi_last_server_pull',
    LAST_SERVER_PUSH: 'smsi_last_server_push',

    // Configuration serveur
    SERVER_CONFIG: 'smsi_server_sync_cfg',
    PASSWORD_SESSION: 'smsi_server_sync_pwd_session',
    PASSWORD_PERSIST: 'smsi_server_sync_pwd_persist',

    // Mode déploiement
    DEPLOYMENT_MODE: 'smsi_deployment_mode',
    SETUP_COMPLETED: 'smsi_setup_completed',

    // Licence serveur
    SERVER_LICENSE: 'smsi_server_license',
    SERVER_LICENSE_ACTIVATED: 'smsi_server_license_activated',

    // Licence Corporate Local
    CORPORATE_TRIAL_START: 'smsi_corporate_trial_start',
    CORPORATE_TRIAL_FP: 'smsi_corporate_trial_fp',
    CORPORATE_LICENSE_KEY: 'smsi_corporate_license_key',

    // UI / Préférences
    THEME: 'smsi_theme',
    WELCOME_SEEN: 'smsi_welcome_seen',
    EDIT_PASSWORD_HASH: 'smsi_edit_password_hash',
    HISTORY_LIMIT: 'smsi_history_limit'
  };

  // Clé de stockage du sel pour le chiffrement du mot de passe
  var SALT_KEY = 'smsi_storage_key_salt';
  var ENC_PREFIX = 'enc:';

  // Version actuelle du schéma de données
  var DATA_VERSION = 1;

  // ============================================================
  // Chiffrement du mot de passe (AES-GCM via Web Crypto API)
  // ============================================================

  function hasCryptoSupport() {
    try {
      return !!(window.crypto && window.crypto.subtle && typeof window.crypto.subtle.deriveKey === 'function');
    } catch (e) { return false; }
  }

  function getOrCreateSalt() {
    try {
      var existing = localStorage.getItem(SALT_KEY);
      if (existing) return existing;
      var salt = window.crypto.getRandomValues(new Uint8Array(16));
      var hex = Array.from(salt).map(function(b) { return b.toString(16).padStart(2, '0'); }).join('');
      localStorage.setItem(SALT_KEY, hex);
      return hex;
    } catch (e) {
      void 0;
      // Return an ephemeral salt so encryption can still proceed this session
      var ephemeral = window.crypto.getRandomValues(new Uint8Array(16));
      return Array.from(ephemeral).map(function(b) { return b.toString(16).padStart(2, '0'); }).join('');
    }
  }

  function hexToBytes(hex) {
    var bytes = new Uint8Array(hex.length / 2);
    for (var i = 0; i < hex.length; i += 2) {
      bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
    }
    return bytes;
  }

  async function deriveKey(salt) {
    var enc = new TextEncoder();
    var origin = window.location.origin !== 'null' ? window.location.origin : 'file-local-csi';
    var keyMaterial = await window.crypto.subtle.importKey(
      'raw', enc.encode(origin + ':csi-storage'),
      'PBKDF2', false, ['deriveKey']
    );
    return window.crypto.subtle.deriveKey(
      { name: 'PBKDF2', salt: hexToBytes(salt), iterations: 100000, hash: 'SHA-256' },
      keyMaterial,
      { name: 'AES-GCM', length: 256 },
      false,
      ['encrypt', 'decrypt']
    );
  }

  async function encryptPassword(password) {
    try {
      if (!hasCryptoSupport() || !password) return password || '';
      var salt = getOrCreateSalt();
      var key = await deriveKey(salt);
      var iv = window.crypto.getRandomValues(new Uint8Array(12));
      var enc = new TextEncoder();
      var ciphertext = await window.crypto.subtle.encrypt(
        { name: 'AES-GCM', iv: iv }, key, enc.encode(password)
      );
      var ivHex = Array.from(iv).map(function(b) { return b.toString(16).padStart(2, '0'); }).join('');
      var ctHex = Array.from(new Uint8Array(ciphertext)).map(function(b) { return b.toString(16).padStart(2, '0'); }).join('');
      return ENC_PREFIX + ivHex + ':' + ctHex;
    } catch (e) {
      void 0;
      return password || '';
    }
  }

  async function decryptPassword(stored) {
    try {
      if (!stored || !stored.startsWith(ENC_PREFIX) || !hasCryptoSupport()) return stored || '';
      var payload = stored.slice(ENC_PREFIX.length);
      var parts = payload.split(':');
      if (parts.length !== 2) return stored;
      var iv = hexToBytes(parts[0]);
      var ciphertext = hexToBytes(parts[1]);
      var salt = localStorage.getItem(SALT_KEY);
      if (!salt) return ''; // salt lost, cannot decrypt
      var key = await deriveKey(salt);
      var decrypted = await window.crypto.subtle.decrypt(
        { name: 'AES-GCM', iv: iv }, key, ciphertext
      );
      return new TextDecoder().decode(decrypted);
    } catch (e) {
      void 0;
      return '';
    }
  }

  // ============================================================
  // Utilitaires internes
  // ============================================================

  function safeJsonParse(str, defaultValue) {
    if (!str) return defaultValue;
    try {
      return JSON.parse(str);
    } catch (e) {
      void 0;
      return defaultValue;
    }
  }

  function safeJsonStringify(obj) {
    try {
      return JSON.stringify(obj);
    } catch (e) {
      void 0;
      return null;
    }
  }

  // ============================================================
  // API Storage
  // ============================================================

  var Storage = {
    // Exposer les clés pour référence externe
    KEYS: KEYS,
    DATA_VERSION: DATA_VERSION,

    // ----------------------------------------------------------
    // Détection du mode serveur (centralisée)
    // ----------------------------------------------------------

    /**
     * Vérifie si l'application tourne en mode serveur (HTTP/HTTPS).
     * En mode serveur, les données métier ne doivent PAS être stockées
     * dans localStorage — le serveur est la seule source de vérité.
     * @returns {boolean}
     */
    isServerMode: function() {
      return window.location.protocol !== 'file:';
    },

    // ----------------------------------------------------------
    // Données principales (smsi_data)
    // ----------------------------------------------------------

    /**
     * Récupère les données de l'application.
     * En mode serveur : retourne null (les données sont en mémoire via appData).
     * En mode local : lit depuis localStorage.
     * @returns {Object|null} Les données ou null si absentes/invalides
     */
    getData: function() {
      if (this.isServerMode()) {
        // Mode serveur : pas de lecture localStorage pour les données métier
        return null;
      }
      return safeJsonParse(localStorage.getItem(KEYS.DATA), null);
    },

    /**
     * Sauvegarde les données de l'application.
     * En mode serveur : no-op (les données sont pushées directement au serveur).
     * En mode local : écrit dans localStorage.
     * @param {Object} data - Les données à sauvegarder
     * @returns {boolean} Succès de l'opération
     */
    setData: function(data) {
      if (!data) return false;
      // Ajouter la version si absente
      if (!data._version) {
        data._version = DATA_VERSION;
      }
      // Mode serveur : pas d'écriture localStorage pour les données métier
      if (this.isServerMode()) {
        return true; // Succès logique — les données vivent en mémoire + serveur
      }
      var json = safeJsonStringify(data);
      if (!json) return false;
      try {
        localStorage.setItem(KEYS.DATA, json);
        localStorage.setItem(KEYS.LAST_SAVE, new Date().toISOString());
        return true;
      } catch (e) {
        void 0;
        return false;
      }
    },

    /**
     * Vérifie si des données utilisateur existent (pas juste les défauts ISO)
     * @returns {boolean}
     */
    hasUserData: function() {
      // En mode serveur, vérifier appData en mémoire
      var data = this.isServerMode() ? (window.appData || null) : this.getData();
      if (!data) return false;

      // Actions ou risques = données utilisateur
      if (data.actions && data.actions.length > 0) return true;
      if (data.risks && data.risks.length > 0) return true;

      // Contrôles modifiés
      if (data.controls && data.controls.length > 0) {
        var defaultStatuses = ['non_implemente', 'Non évalué', '', null, undefined];
        var hasModified = data.controls.some(function(c) {
          var isDefault = defaultStatuses.indexOf(c.status) !== -1;
          return (!isDefault) ||
                 (c.notes && c.notes.trim() !== '') ||
                 (c.responsable && c.responsable.trim() !== '');
        });
        if (hasModified) return true;
      }

      return false;
    },

    // ----------------------------------------------------------
    // Configuration serveur
    // ----------------------------------------------------------

    /**
     * Récupère la configuration serveur
     * @returns {Object} Configuration {baseUrl?, rememberPassword?}
     */
    getServerConfig: function() {
      return safeJsonParse(localStorage.getItem(KEYS.SERVER_CONFIG), {});
    },

    /**
     * Sauvegarde la configuration serveur
     * @param {Object} config
     */
    setServerConfig: function(config) {
      try {
        localStorage.setItem(KEYS.SERVER_CONFIG, safeJsonStringify(config || {}));
      } catch(e) {
        void 0;
      }
    },

    /**
     * Récupère le mot de passe (session ou persisté)
     * @returns {string} Mot de passe ou chaîne vide
     */
    getPassword: function() {
      // Priorité au mot de passe de session (clair)
      var sessionPwd = sessionStorage.getItem(KEYS.PASSWORD_SESSION);
      if (sessionPwd) return sessionPwd;

      // Sinon, mot de passe persisté si autorisé
      var config = this.getServerConfig();
      if (config.rememberPassword) {
        var stored = localStorage.getItem(KEYS.PASSWORD_PERSIST) || '';
        // If encrypted, return a promise-like placeholder — callers should use getPasswordAsync
        if (stored.startsWith(ENC_PREFIX)) {
          // Synchronous fallback: return empty, rely on getPasswordAsync for actual value
          return '';
        }
        return stored;
      }

      return '';
    },

    /**
     * Récupère le mot de passe de manière asynchrone (décryptage si nécessaire)
     * @returns {Promise<string>} Mot de passe ou chaîne vide
     */
    getPasswordAsync: async function() {
      // Priorité au mot de passe de session (clair)
      var sessionPwd = sessionStorage.getItem(KEYS.PASSWORD_SESSION);
      if (sessionPwd) return sessionPwd;

      // Sinon, mot de passe persisté si autorisé
      var config = this.getServerConfig();
      if (config.rememberPassword) {
        var stored = localStorage.getItem(KEYS.PASSWORD_PERSIST) || '';
        if (stored.startsWith(ENC_PREFIX)) {
          var decrypted = await decryptPassword(stored);
          // Cache in session for sync getPassword() calls
          if (decrypted) sessionStorage.setItem(KEYS.PASSWORD_SESSION, decrypted);
          return decrypted;
        }
        // Migration transparente: re-encrypt cleartext password
        if (stored && hasCryptoSupport()) {
          try {
            var encrypted = await encryptPassword(stored);
            localStorage.setItem(KEYS.PASSWORD_PERSIST, encrypted);
            sessionStorage.setItem(KEYS.PASSWORD_SESSION, stored);
          } catch(e) { /* ignore migration errors */ }
        }
        return stored;
      }

      return '';
    },

    /**
     * Sauvegarde le mot de passe
     * @param {string} password
     * @param {boolean} remember - Persister entre sessions
     */
    setPassword: function(password, remember) {
      // Toujours sauver en session (session storage = éphémère, clair OK)
      sessionStorage.setItem(KEYS.PASSWORD_SESSION, password || '');

      // Persister si demandé — chiffrer avec AES-GCM
      if (remember) {
        var config = this.getServerConfig();
        config.rememberPassword = true;
        this.setServerConfig(config);
        // H24: Write cleartext immediately as fallback, then overwrite with encrypted
        try { localStorage.setItem(KEYS.PASSWORD_PERSIST, password || ''); } catch(e) {}
        if (hasCryptoSupport()) {
          encryptPassword(password || '').then(function(encrypted) {
            try { localStorage.setItem(KEYS.PASSWORD_PERSIST, encrypted); } catch(e) {}
          }).catch(function() { /* already stored in clear */ });
        }
      }
    },

    /**
     * Efface le mot de passe
     */
    clearPassword: function() {
      sessionStorage.removeItem(KEYS.PASSWORD_SESSION);
      localStorage.removeItem(KEYS.PASSWORD_PERSIST);
      var config = this.getServerConfig();
      config.rememberPassword = false;
      this.setServerConfig(config);
    },

    // ----------------------------------------------------------
    // Mode déploiement
    // ----------------------------------------------------------

    /**
     * Récupère le mode de déploiement
     * @returns {string} 'local', 'server', ou 'unknown'
     */
    getDeploymentMode: function() {
      return localStorage.getItem(KEYS.DEPLOYMENT_MODE) || 'unknown';
    },

    /**
     * Définit le mode de déploiement
     * @param {string} mode - 'local' ou 'server'
     */
    setDeploymentMode: function(mode) {
      try {
        localStorage.setItem(KEYS.DEPLOYMENT_MODE, mode);
      } catch(e) {
        void 0;
      }
    },

    /**
     * Vérifie si le setup initial est terminé
     * @returns {boolean}
     */
    isSetupCompleted: function() {
      return localStorage.getItem(KEYS.SETUP_COMPLETED) === '1';
    },

    /**
     * Marque le setup comme terminé
     * @param {string} mode - Mode choisi ('local' ou 'server')
     */
    markSetupCompleted: function(mode) {
      try {
        localStorage.setItem(KEYS.SETUP_COMPLETED, '1');
      } catch(e) {
        void 0;
      }
      this.setDeploymentMode(mode);
    },

    // ----------------------------------------------------------
    // Timestamps de synchronisation
    // ----------------------------------------------------------

    /**
     * Met à jour le timestamp de dernière synchro serveur (push)
     */
    updateLastPush: function() {
      this._lastPushTime = new Date().toISOString();
      if (!this.isServerMode()) {
        try {
          localStorage.setItem(KEYS.LAST_SERVER_PUSH, this._lastPushTime);
        } catch(e) {
          void 0;
        }
      }
    },

    /**
     * Met à jour le timestamp de dernière synchro serveur (pull)
     */
    updateLastPull: function() {
      this._lastPullTime = new Date().toISOString();
      if (!this.isServerMode()) {
        try {
          localStorage.setItem(KEYS.LAST_SERVER_PULL, this._lastPullTime);
        } catch(e) {
          void 0;
        }
      }
    },

    /**
     * Récupère les timestamps de synchronisation
     * @returns {Object} {lastSave, lastPush, lastPull}
     */
    getSyncTimestamps: function() {
      if (this.isServerMode()) {
        return {
          lastSave: this._lastSaveTime || null,
          lastPush: this._lastPushTime || null,
          lastPull: this._lastPullTime || null
        };
      }
      try {
        return {
          lastSave: localStorage.getItem(KEYS.LAST_SAVE),
          lastPush: localStorage.getItem(KEYS.LAST_SERVER_PUSH),
          lastPull: localStorage.getItem(KEYS.LAST_SERVER_PULL)
        };
      } catch(e) {
        void 0;
        return { lastSave: null, lastPush: null, lastPull: null };
      }
    },

    // ----------------------------------------------------------
    // Préférences UI
    // ----------------------------------------------------------

    /**
     * Récupère le thème actuel
     * @returns {string}
     */
    getTheme: function() {
      return localStorage.getItem(KEYS.THEME) || 'poudre';
    },

    /**
     * Définit le thème
     * @param {string} theme
     */
    setTheme: function(theme) {
      try {
        localStorage.setItem(KEYS.THEME, theme);
      } catch(e) {
        void 0;
      }
    },

    /**
     * Vérifie si le welcome a été vu
     * @returns {boolean}
     */
    isWelcomeSeen: function() {
      return localStorage.getItem(KEYS.WELCOME_SEEN) === '1';
    },

    /**
     * Marque le welcome comme vu
     */
    markWelcomeSeen: function() {
      try {
        localStorage.setItem(KEYS.WELCOME_SEEN, '1');
      } catch(e) {
        void 0;
      }
    },

    // ----------------------------------------------------------
    // Migration de données
    // ----------------------------------------------------------

    /**
     * Migre les données vers la version actuelle si nécessaire
     * @returns {boolean} true si migration effectuée
     */
    migrateIfNeeded: function() {
      var data = this.getData();
      if (!data) return false;

      var currentVersion = data._version || 0;
      var migrated = false;

      // Migration v0 -> v1 : Ajouter le champ version
      if (currentVersion < 1) {
        data._version = 1;
        data._migratedAt = new Date().toISOString();
        migrated = true;
        void 0;
      }

      // Futures migrations ici...
      // if (currentVersion < 2) { ... }

      if (migrated) {
        this.setData(data);
      }

      return migrated;
    },

    // ----------------------------------------------------------
    // Utilitaires
    // ----------------------------------------------------------

    /**
     * Efface toutes les données CSI
     */
    clearAll: function() {
      Object.values(KEYS).forEach(function(key) {
        try { localStorage.removeItem(key); } catch(e) {}
        try { sessionStorage.removeItem(key); } catch(e) {}
      });
      // Also clear salt and auth tokens not in KEYS
      try { localStorage.removeItem(SALT_KEY); } catch(e) {}
      try { sessionStorage.removeItem('csi_auth_token'); } catch(e) {}
      try { sessionStorage.removeItem('csi_auth_user'); } catch(e) {}
    },

    /**
     * Exporte toutes les clés CSI pour debug
     * @returns {Object}
     */
    exportAll: function() {
      var result = {};
      Object.keys(KEYS).forEach(function(name) {
        var key = KEYS[name];
        var localValue = localStorage.getItem(key);
        var sessionValue = sessionStorage.getItem(key);
        if (localValue || sessionValue) {
          result[name] = {
            key: key,
            local: localValue,
            session: sessionValue
          };
        }
      });
      return result;
    },

    // ----------------------------------------------------------
    // Licence serveur (legacy — préférer CSI_LicenseManager)
    // ----------------------------------------------------------

    /**
     * @deprecated Utiliser CSI_LicenseManager.isServerMode() à la place.
     * Conservé pour compatibilité ascendante avec déploiements existants.
     */
    isServerLicenseActivated: function() {
      return localStorage.getItem(KEYS.SERVER_LICENSE_ACTIVATED) === '1';
    },

    /** @deprecated Utiliser CSI_LicenseManager.getLicense() */
    getServerLicense: function() {
      return safeJsonParse(localStorage.getItem(KEYS.SERVER_LICENSE), null);
    },

    /** @deprecated Licence désormais dans config/license.json */
    activateServerLicense: function(licenseData) {
      try {
        localStorage.setItem(KEYS.SERVER_LICENSE, safeJsonStringify(licenseData));
        localStorage.setItem(KEYS.SERVER_LICENSE_ACTIVATED, '1');
      } catch(e) {
        void 0;
      }
    },

    /** @deprecated */
    deactivateServerLicense: function() {
      try {
        localStorage.removeItem(KEYS.SERVER_LICENSE);
        localStorage.removeItem(KEYS.SERVER_LICENSE_ACTIVATED);
      } catch(e) {
        void 0;
      }
    }
  };

  // ============================================================
  // Initialisation
  // ============================================================

  // Exécuter la migration au chargement
  Storage.migrateIfNeeded();

  // Warm session cache: decrypt password early so sync getPassword() works
  if (hasCryptoSupport()) {
    try { Storage.getPasswordAsync().catch(function() {}); } catch(e) {}
  }

  // Enregistrer dans le registre CSI si disponible
  if (window.CSI && window.CSI.register) {
    window.CSI.register('storage', {
      exports: Storage
    });
  }

  // Exposer globalement
  window.CSI_Storage = Storage;

  void 0;

})();
