/**
 * Episteme Presentation Renderer
 *
 * Data-driven slide rendering with multi-deck support.
 *
 * Modes:
 *   flat     - single deck, slides left/right (default Reveal.js)
 *   combined - menu column (↓ browse, → enter), decks are vertical (↓↑ navigate, ← back)
 *
 * Slide types are registered in RENDERERS. To add a new type, add one function.
 */

(async function () {
  const dataUrl = window.PRESENTATION_DATA_URL || '/generated/stemedb.json';

  let data;
  try {
    const resp = await fetch(dataUrl);
    data = await resp.json();
  } catch (err) {
    document.getElementById('slides').innerHTML = `
      <section class="title-slide">
        <h1>Error Loading Presentation</h1>
        <p class="subtitle">Could not load ${dataUrl}</p>
        <p>Run: <code>npm run generate:all</code></p>
      </section>`;
    Reveal.initialize();
    return;
  }

  const root = document.getElementById('slides');
  const isCombined = !!data.combined;

  // ── Utilities ──────────────────────────────────────────────

  function esc(text) {
    const el = document.createElement('div');
    el.textContent = text;
    return el.innerHTML;
  }

  function actorInitials(actor) {
    if (!actor?.label) return '??';
    return actor.label.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2);
  }

  function fragmentList(items, cls) {
    return `<ul class="${cls}">${items.map(p => `<li class="fragment">${p}</li>`).join('')}</ul>`;
  }

  // ── Slide-Type Registry ────────────────────────────────────
  //
  // Each renderer receives (slide, ctx) and returns { css?, attrs?, html }.
  // ctx = { actors, sectionNum }

  const RENDERERS = {
    title() {
      return {
        css: 'title-slide',
        html: '<div class="slide-title"><h1 class="brand">stemedb</h1></div>',
      };
    },

    hook(slide) {
      return {
        css: 'hook-slide',
        html: `<div class="slide-hook">
          <p class="hook-line">${slide.line}</p>
          ${slide.subline ? `<p class="hook-subline fragment">${slide.subline}</p>` : ''}
        </div>`,
      };
    },

    code(slide) {
      return {
        css: 'code-slide',
        html: `<div class="slide-code">
          <h2>${slide.title}</h2>
          <div class="code-block"><pre><code>${esc(slide.code.trim())}</code></pre></div>
        </div>`,
      };
    },

    problem(slide) {
      return {
        css: 'problem-slide',
        html: `<div class="slide-problem">
          <h2>${slide.title}</h2>
          ${fragmentList(slide.points, 'problem-points')}
        </div>`,
      };
    },

    insight(slide) {
      return {
        css: 'insight-slide',
        html: `<div class="slide-insight">
          <h2>${slide.title}</h2>
          ${fragmentList(slide.points, 'insight-points')}
        </div>`,
      };
    },

    vision(slide) {
      return {
        css: 'vision-slide',
        html: `<div class="slide-vision">
          <h2>${slide.title}</h2>
          ${fragmentList(slide.points, 'vision-points')}
          ${slide.tagline ? `<p class="vision-tagline fragment">${slide.tagline}</p>` : ''}
        </div>`,
      };
    },

    'section-title'(slide, ctx) {
      ctx.sectionNum++;
      return {
        html: `<div class="slide-section-title">
          <span class="section-number">Section ${ctx.sectionNum}</span>
          <h2>${slide.title}</h2>
          <p class="subtitle">${slide.subtitle}</p>
          <p class="description">${slide.description.trim()}</p>
        </div>`,
      };
    },

    contrast(slide) {
      return {
        css: 'contrast-slide',
        html: `<div class="slide-contrast">
          <h2>${slide.title}</h2>
          <div class="contrast-container">
            <div class="contrast-side before fragment">
              <h3>${slide.before.title}</h3>
              <ul>${slide.before.points.map(p => `<li>${p}</li>`).join('')}</ul>
            </div>
            <div class="contrast-side after fragment">
              <h3>${slide.after.title}</h3>
              <ul>${slide.after.points.map(p => `<li>${p}</li>`).join('')}</ul>
            </div>
          </div>
        </div>`,
      };
    },

    sequence(slide, ctx) {
      return {
        attrs: { 'data-auto-animate': '' },
        html: renderSequence(slide, ctx.actors),
      };
    },
  };

  // ── Section Factory ────────────────────────────────────────

  function createSection(slide, ctx) {
    const render = RENDERERS[slide.type];
    if (!render) return null;

    const { css, attrs, html } = render(slide, ctx);
    const el = document.createElement('section');
    if (css) el.classList.add(css);
    if (attrs) Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v));
    el.innerHTML = html;
    return el;
  }

  // ── Build: Flat (single deck) ──────────────────────────────

  function buildFlat(slides, actors) {
    const ctx = { actors: actors || {}, sectionNum: 0 };
    for (const slide of slides) {
      const el = createSection(slide, ctx);
      if (el) root.appendChild(el);
    }
  }

  // ── Build: Combined (multi-deck) ──────────────────────────

  function buildCombined(decks) {
    // Column 0: vertical menu stack
    const menu = document.createElement('section');

    // Title (reuses the registered title renderer — single source of truth)
    menu.appendChild(createSection({ type: 'title' }, { actors: {}, sectionNum: 0 }));

    // Deck entry cards
    decks.forEach((deck, i) => {
      const card = document.createElement('section');
      card.classList.add('menu-slide');
      card.innerHTML = `<div class="slide-menu-card">
        <span class="menu-card-number">${String(i + 1).padStart(2, '0')}</span>
        <h2>${deck.meta.title}</h2>
        ${deck.meta.subtitle ? `<p class="menu-card-subtitle">${deck.meta.subtitle}</p>` : ''}
        <p class="menu-card-hint">press <span class="key-hint">&rarr;</span> to enter</p>
      </div>`;
      menu.appendChild(card);
    });

    root.appendChild(menu);

    // Columns 1-N: each deck as a horizontal section wrapping vertical slides
    for (const deck of decks) {
      const col = document.createElement('section');
      const ctx = { actors: deck.actors || {}, sectionNum: 0 };
      for (const slide of deck.slides) {
        if (slide.type === 'title') continue; // menu is the landing
        const el = createSection(slide, ctx);
        if (el) col.appendChild(el);
      }
      root.appendChild(col);
    }
  }

  // ── Sequence Slide (complex layout, kept separate) ─────────

  function renderSequence(slide, allActors) {
    const actors = slide.actors.map(id =>
      typeof id === 'string'
        ? allActors[id] || { id, label: id, color: '#666666' }
        : id
    );

    const lookup = {};
    actors.forEach(a => {
      lookup[a.id] = a;
      const key = Object.keys(allActors).find(k => allActors[k].id === a.id);
      if (key) lookup[key] = a;
    });

    const actorsHtml = actors.map(a => `
      <div class="actor">
        <div class="actor-icon" style="background-color:${a.color}">${actorInitials(a)}</div>
        <span class="actor-label">${a.label}</span>
      </div>`).join('');

    const stepsHtml = slide.steps.map((step, i) => {
      const cls = step.danger ? 'danger' : step.success ? 'success' : step.warning ? 'warning' : '';
      const from = lookup[step.from] || allActors[step.from] || { label: step.from };
      const to = lookup[step.to] || allActors[step.to] || { label: step.to };
      return `
        <div class="step-card ${cls} fragment" data-fragment-index="${i}">
          <div class="step-index">${i + 1}</div>
          <div class="step-content">
            <div class="step-header">
              <div class="step-actors">
                <span class="step-from">${from.label}</span>
                <span class="step-arrow">&rarr;</span>
                <span class="step-to">${to.label}</span>
              </div>
              <span class="step-action">${step.action}</span>
            </div>
            <div class="step-label">${step.label}</div>
            ${step.note ? `<div class="step-note">${step.note}</div>` : ''}
            ${step.callout ? `<div class="step-callout">${step.callout}</div>` : ''}
          </div>
        </div>`;
    }).join('');

    return `<div class="slide-sequence">
      <div class="header"><h3>${slide.title}</h3></div>
      <div class="actors-row">${actorsHtml}</div>
      <div class="steps-container">${stepsHtml}</div>
    </div>`;
  }

  // ── Keyboard: Combined Mode ────────────────────────────────
  //
  // Menu (h=0): ↓↑ browse cards, → enter deck
  // Deck (h>0): ↓↑ navigate slides, ← back to menu
  //             → also advances (alias for ↓) so arrow-mashing works

  function combinedKeys() {
    return {
      // → : menu → enter deck; inside deck → next slide
      39: function () {
        const { h, v } = Reveal.getIndices();
        if (h === 0) {
          Reveal.slide(v > 0 ? v : 1, 0);
        } else {
          Reveal.down();
        }
      },
      // ← : first slide of deck → back to its menu card; deeper → prev slide
      37: function () {
        const { h, v } = Reveal.getIndices();
        if (h > 0 && v === 0) {
          Reveal.slide(0, h);
        } else if (h > 0) {
          Reveal.up();
        }
      },
    };
  }

  // ── Render & Initialize ────────────────────────────────────

  if (isCombined) {
    buildCombined(data.decks);
  } else {
    buildFlat(data.slides, data.actors || {});
  }

  Reveal.initialize({
    hash: true,
    history: true,
    controls: true,
    progress: true,
    center: true,
    transition: 'fade',
    transitionSpeed: 'fast',
    keyboard: isCombined ? combinedKeys() : { 39: 'next', 37: 'prev' },
  });

  Reveal.on('fragmentshown', e => e.fragment.classList.add('visible'));
  Reveal.on('fragmenthidden', e => e.fragment.classList.remove('visible'));

})();
