'use strict';
/*
 * LabLoader — ленивый загрузчик кода симуляций (контент-движок, Фаза 3).
 *
 * Тяжёлый код симуляций (~2.5 МБ) и three.js (~600 КБ) больше НЕ грузятся на старте.
 * При открытии симуляции LabLoader.ensure(id) подгружает её файлы (по манифесту
 * window.SIM_DEPS из _sim_deps.js) и, при необходимости, three.js — затем резолвит.
 *
 * Гарантия корректности (самовосстановление): если после загрузки указанных файлов
 * глобальная open-функция (SIM_DEPS[id].open, напр. "_openPendulum") всё ещё не
 * определена, грузятся ВСЕ ленивые файлы (window.LAB_LAZY_FILES). Поэтому ошибка в
 * манифесте не может «сломать» симуляцию — в худшем случае грузится больше файлов
 * (поведение как до Фазы 3). Манифест лишь оптимизирует объём загрузки.
 *
 * Все загрузки кешируются (по URL) и дедуплицируются.
 */
(function () {
  var BASE = '/js/labs/';
  var THREE_URL = 'https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js';
  var _cache = {};       // url -> Promise
  var _allLoaded = false;

  function loadScript(url) {
    if (_cache[url]) return _cache[url];
    _cache[url] = new Promise(function (resolve, reject) {
      var s = document.createElement('script');
      s.src = url;
      s.async = false;   // сохранить порядок при добавлении нескольких сразу
      s.onload = function () { resolve(url); };
      s.onerror = function () { delete _cache[url]; reject(new Error('LabLoader: не удалось загрузить ' + url)); };
      document.head.appendChild(s);
    });
    return _cache[url];
  }

  function ensureThree() {
    if (typeof window.THREE !== 'undefined') return Promise.resolve();
    return loadScript(THREE_URL);
  }

  function loadFiles(files) {
    return Promise.all((files || []).map(function (f) { return loadScript(BASE + f); }));
  }

  function loadAllLazy() {
    if (_allLoaded) return Promise.resolve();
    var list = window.LAB_LAZY_FILES || [];
    return loadFiles(list).then(function () { _allLoaded = true; });
  }

  // ensure(id): загрузить всё необходимое для симуляции id, вернуть Promise.
  function ensure(id) {
    var dep = (window.SIM_DEPS && window.SIM_DEPS[id]) || null;
    if (!dep) {
      // нет манифеста для id — безопасно грузим всё
      return loadAllLazy();
    }
    var p = dep.three ? ensureThree() : Promise.resolve();
    return p
      .then(function () { return loadFiles(dep.files); })
      .then(function () {
        var openName = dep.open;
        if (openName && typeof window[openName] !== 'function') {
          if (window.console) console.warn('[LabLoader] самовосстановление для "' + id + '": ' + openName + ' не найдена после загрузки ' + JSON.stringify(dep.files) + ' — гружу все ленивые файлы');
          return loadAllLazy();
        }
      });
  }

  window.LabLoader = {
    ensure: ensure,
    ensureThree: ensureThree,
    loadScript: loadScript,
    loadAllLazy: loadAllLazy
  };
})();
