// Theme registry
// ---------------
// Discovers themes from frontend/themes/<name>/ via the backend
// /api/themes/list endpoint, <link>s each one's CSS into <head>, and
// exposes the list at window.ThemeRegistry for the topbar dropdown.
//
// Every theme — built-in or custom — lives in frontend/themes/<name>/.
// The inline bootstrap in index.html already <link>s the saved theme
// synchronously before first paint; this script <link>s the rest so the
// dropdown can switch between them without another network round-trip.
//
// If the API fails completely, the dropdown falls back to a single
// option (the currently-loaded theme from data-theme). The user can't
// switch, but the page still renders correctly.

(function () {
  var currentTheme = document.documentElement.getAttribute('data-theme') || 'nebula';
  var state = {
    themes: [{
      name: currentTheme,
      displayName: currentTheme,
      css: '/themes/' + currentTheme + '/theme.css',
      builtin: false,
    }],
    loaded: false,
    listeners: [],
  };

  function notify() {
    state.listeners.forEach(function (cb) {
      try { cb(state.themes); } catch (_) { /* swallow */ }
    });
  }

  function linkThemeCss(theme) {
    // The inline bootstrap already linked the current theme; this dedupes.
    if (document.head.querySelector('link[data-theme-css="' + theme.name + '"]')) return;
    var link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = theme.css;
    link.setAttribute('data-theme-css', theme.name);
    document.head.appendChild(link);
  }

  function fetchThemes() {
    return fetch('/api/themes/list', { credentials: 'same-origin' })
      .then(function (r) { return r.ok ? r.json() : []; })
      .then(function (list) {
        if (Array.isArray(list) && list.length) state.themes = list;
        state.themes.forEach(linkThemeCss);
        state.loaded = true;
        notify();
      })
      .catch(function () {
        // Network/API failure — keep the built-in fallback list.
        state.loaded = true;
        notify();
      });
  }

  window.ThemeRegistry = {
    /* Synchronous accessor — returns whatever list we have, even if the
       fetch is still in flight. Always includes at least the built-ins. */
    list: function () { return state.themes.slice(); },

    /* True once /api/themes/list has resolved (success or failure). */
    isLoaded: function () { return state.loaded; },

    /* Subscribe to list updates. Called immediately with the current
       list and again after the fetch resolves. */
    onChange: function (cb) {
      state.listeners.push(cb);
      try { cb(state.themes); } catch (_) { /* swallow */ }
    },

    /* Manually trigger a refresh — used after the user drops a new
       theme folder and hits "reload themes" (no UI for that yet). */
    refresh: fetchThemes,
  };

  fetchThemes();
})();
