(async function () {
  'use strict';

  const SECTIONS = [
    's-voices', 's-clone', 's-design', 's-studio', 's-tryout', 's-rehearser',
    's-reader', 's-performance', 's-routing', 's-connect', 's-settings',
    's-llms', 's-conversation', 's-characters',
  ];

  function _storedSection() {
    try { return localStorage.getItem('ttsvc_section') || ''; } catch (_) { return ''; }
  }
  function _hashSection() {
    var raw = String(location.hash || '').replace(/^#/, '').trim();
    if (!raw) return '';
    if (raw.indexOf('section=') === 0) raw = raw.slice(8);
    raw = decodeURIComponent(raw).replace(/^\/?/, '');
    return SECTIONS.indexOf(raw) !== -1 ? raw : '';
  }

  // Determine which section to show first (same logic as nav.js): hash > stored > My Voices.
  var _savedSection = _storedSection();
  var _activeSection = _hashSection() || ((_savedSection && SECTIONS.indexOf(_savedSection) !== -1) ? _savedSection : 's-voices');

  // ── Fetch app version once for JS cache-busting ──────────────────────────
  var _appVersion = 'dev';
  try {
    var _vr = await fetch('/api/version');
    var _vd = await _vr.json();
    _appVersion = _vd.version || _appVersion;
  } catch (_) {}

  var _ts = Date.now(); // sections always fresh during a session
  // Append session timestamp so that a version bump + container restart
  // always invalidates previously cached JS, even on the same version string.
  _appVersion = _appVersion + '-' + _ts;

  function _inject(id, html) {
    var el = document.getElementById(id);
    if (el) el.innerHTML = html;
  }

  // ── 1. Load ONLY the active section before anything else ─────────────────
  // Feature modules set up DOM event listeners — the active section's elements
  // must exist when JS runs. Other sections are loaded in step 2.
  try {
    var _ar = await fetch('/static/sections/' + _activeSection + '.html?v=' + _ts);
    if (!_ar.ok) throw new Error(_ar.status + ' ' + _ar.statusText);
    _inject(_activeSection, await _ar.text());
  } catch (e) {
    var _ael = document.getElementById(_activeSection);
    if (_ael) _ael.innerHTML =
      '<p style="color:var(--red);padding:24px">Failed to load section <b>' +
      _activeSection + '</b>: ' + e.message + '</p>';
  }

  // ── 2. Fetch remaining sections in background (parallel with JS loading) ──
  // These run concurrently with utils + settings below. Because section HTML
  // files are much smaller than JS, they finish before the feature-module batch
  // needs them.
  var _bgSections = Promise.all(
    SECTIONS.filter(function (id) { return id !== _activeSection; })
      .map(async function (id) {
        try {
          var res = await fetch('/static/sections/' + id + '.html?v=' + _ts);
          if (!res.ok) throw new Error(res.status + ' ' + res.statusText);
          _inject(id, await res.text());
        } catch (e) {
          var el = document.getElementById(id);
          if (el) el.innerHTML =
            '<p style="color:var(--red);padding:24px">Failed to load section <b>' +
            id + '</b>: ' + e.message + '</p>';
        }
      })
  );

  // ── 3. Load JS in parallel batches ────────────────────────────────────────
  // Scripts with async=false are FETCHED in parallel but EXECUTED in DOM
  // insertion order — safe for modules that share a global scope.
  function _load(src) {
    return new Promise(function (resolve, reject) {
      var s = document.createElement('script');
      s.src = src + '?v=' + _appVersion;
      s.async = false;   // fetch in parallel, execute in DOM order
      s.onload  = resolve;
      s.onerror = function () { reject(new Error('Failed to load ' + src)); };
      document.body.appendChild(s);
    });
  }

  function _loadBatch(srcs) {
    return Promise.all(srcs.map(_load));
  }

  // A — foundation (sequential: each must finish before the next batch starts)
  await _load('/static/js/utils.js');
  await _load('/static/js/i18n.js');     // defines window.t / applyI18n before features run
  await _load('/static/js/settings.js');

  // Wait for background sections BEFORE feature modules run.
  // Feature modules set up event listeners on DOM elements; all section HTML
  // must already be injected. On a local server the sections finish well before
  // settings.js completes, so this await is typically instant.
  await _bgSections;

  // C — feature modules (executed in order; share a global scope).
  // Opt-in single bundle (npm run minify) keeps these as one minified request;
  // default loads them individually so editing static/js/* is live without a build.
  var _featureFiles = [
    '/static/js/voice-picker.js',
    '/static/js/benchmark-voice-picker.js',
    '/static/js/voice-inspector.js',
    '/static/js/seed-finder.js',
    '/static/js/voice-sources.js',
    '/static/js/fishaudio-browser.js',
    '/static/js/integrations.js',
    '/static/js/routing.js',
    '/static/js/voice-clone.js',
    '/static/js/voice-library.js',
    '/static/js/tts-preview.js',
    '/static/js/generation.js',
    '/static/js/benchmark.js',
    '/static/js/stt.js',
    '/static/js/rehearser-parse.js',
    '/static/js/rehearser.js',
    '/static/js/reader.js',
    '/static/js/audiobook.js',
    '/static/js/character-sheets.js',
    '/static/js/characters-library.js',
  ];
  var _useBundle = window.APP_USE_BUNDLE === true || location.search.indexOf('bundle=1') !== -1;
  var _bundleOk = false;
  if (_useBundle) {
    try { await _load('/static/dist/main.min.js'); _bundleOk = true; }
    catch (_) { _bundleOk = false; }   // not built / missing → fall back to per-file
  }
  if (!_bundleOk) await _loadBatch(_featureFiles);

  // D — init (needs everything above to be defined)
  await _load('/static/js/init.js');

  // F — navigation (must run before revealing UI so the correct section shows)
  await _load('/static/nav.js');

  // ── Remove skeleton, reveal sections — as soon as nav is ready ──────────
  var sk = document.getElementById('app-skeleton');
  if (sk) {
    sk.classList.add('sk-hidden');
    setTimeout(function () { if (sk.parentNode) sk.parentNode.removeChild(sk); }, 300);
  }
  document.querySelectorAll('.page-section').forEach(function (s) {
    s.style.display = '';
  });

  // ── i18n: add the language picker and translate the (now fully-rendered) UI ──
  if (window.initLangPicker) window.initLangPicker();
  if (window.applyI18n) window.applyI18n(document);
  if (window.initAccessibilityEnhancements) window.initAccessibilityEnhancements();

  // E — post-init modules load in background AFTER the UI is already visible.
  // Engines, AI backends, and conversation load while the user browses other tabs.
  _loadBatch([
    '/static/js/engines.js',
    '/static/js/ai-backends.js',
    '/static/js/conversation.js',
  ]);
})();
