// ============================================================
// LEARNING HUB — User content feed, viewer, quizzes + Admin CMS
// ============================================================

(function() {

  var loaded = false;
  var cmsLoaded = false;
  var currentContent = null;
  var currentView = 'feed'; // 'feed' | 'category' | 'viewer'
  var _bodyEditor = null; // Tiptap Editor instance for body

  // ── Load when tab activated ────────────────────────────────
  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'learning') {
      if (!loaded) { loadFeed(); loadCategories(); loaded = true; wireSearch(); }
    }
    // Load CMS when Content Manager tab is opened
    if (e.detail && e.detail.tab === 'cms') {
      if (!cmsLoaded) { loadCms(); cmsLoaded = true; wireCmsFileInput(); wireCmsTypeSelect(); }
    }
  });

  // ── Event delegation ───────────────────────────────────────
  document.addEventListener('click', function(e) {
    // Slide preview modal controls (checked first — modal is outside CMS)
    if (e.target.closest('#slide-preview-close') || e.target.id === 'slide-preview-overlay') { closeSlideModal(); return; }
    if (e.target.closest('#slide-nav-prev'))  { slideStep(-1); return; }
    if (e.target.closest('#slide-nav-next'))  { slideStep(1);  return; }
    var dot = e.target.closest('.slide-dot');
    if (dot) { renderSlide(parseInt(dot.dataset.idx)); return; }


    // Feed item click
    var feedItem = e.target.closest('.lh-feed-item');
    if (feedItem && feedItem.dataset.slug) {
      loadContent(feedItem.dataset.slug);
      return;
    }

    // Category pill click
    var catPill = e.target.closest('.lh-cat-pill');
    if (catPill && catPill.dataset.slug) {
      if (catPill.dataset.slug === 'all') {
        loadFeed();
        setActiveCatPill('all');
      } else {
        loadCategoryContent(catPill.dataset.slug);
        setActiveCatPill(catPill.dataset.slug);
      }
      return;
    }

    // Back button
    if (e.target.closest('#lh-back')) {
      showFeed();
      return;
    }

    // Submit quiz
    if (e.target.closest('#lh-submit-quiz')) {
      submitQuiz();
      return;
    }

    // ── CMS events ─────────────────────────────
    if (e.target.closest('#btn-lh-refresh-content')) { loadCmsContent(); loadCmsStats(); return; }
    if (e.target.closest('#btn-lh-add-cat')) { addCategory(); return; }
    if (e.target.closest('#btn-lh-new-content')) { openEditor(null, 'article'); return; }
    if (e.target.closest('#btn-lh-new-quiz')) { openEditor(null, 'quiz'); return; }
    if (e.target.closest('#btn-lh-new-pearl')) { openEditor(null, 'pearl'); return; }
    if (e.target.closest('#btn-lh-new-presentation')) { openEditor(null, 'presentation'); return; }
    if (e.target.closest('#btn-lh-close-editor')) { closeEditor(); return; }
    if (e.target.closest('#btn-lh-save-content')) { saveContent(); return; }
    if (e.target.closest('#btn-lh-delete-content')) { showDeleteConfirm(); return; }
    if (e.target.closest('#btn-lh-delete-yes'))     { confirmDelete(); return; }
    if (e.target.closest('#btn-lh-delete-cancel'))  { hideDeleteConfirm(); return; }
    if (e.target.closest('#btn-lh-add-question')) { addQuestionBlock(); return; }

    // Presentation
    if (e.target.closest('#btn-lh-preview-slides'))  { previewSlides(); return; }
    if (e.target.closest('#btn-lh-download-pptx'))   { downloadPptx(); return; }

    // AI panel
    if (e.target.closest('#btn-lh-ai-open'))        { openAiPanel(); return; }
    if (e.target.closest('#btn-lh-ai-close'))        { closeAiPanel(); return; }
    if (e.target.closest('#btn-lh-ai-generate'))     { runAiGenerate(); return; }
    if (e.target.closest('#btn-lh-ai-refine-body'))  { toggleRefineBar(); return; }
    if (e.target.closest('#btn-lh-refine-submit'))   { submitRefineBody(); return; }
    if (e.target.closest('#btn-lh-refine-cancel'))   { toggleRefineBar(false); return; }
    if (e.target.closest('#btn-lh-webdav-refresh'))  { browseWebdav(_aiWebdavCurrentPath); return; }
    if (e.target.closest('#btn-lh-webdav-deselect')) { deselectWebdavFile(); return; }

    // AI tabs
    var aiTab = e.target.closest('.lh-ai-tab');
    if (aiTab && aiTab.dataset.aitab) { switchAiTab(aiTab.dataset.aitab); return; }

    // WebDAV list items
    var wdItem = e.target.closest('.lh-webdav-item');
    if (wdItem) {
      if (wdItem.dataset.isdir === '1') {
        browseWebdav(wdItem.dataset.path);
      } else {
        selectWebdavFile(wdItem.dataset.path, wdItem.dataset.name);
      }
      return;
    }

    // Rich text toggle for question or option
    var rtBtn = e.target.closest('.lh-richtext-btn');
    if (rtBtn) { toggleRichText(rtBtn); return; }

    // CMS content item edit
    var cmsItem = e.target.closest('.lh-cms-content-item');
    if (cmsItem && cmsItem.dataset.id) { openEditor(cmsItem.dataset.id); return; }

    // CMS delete category
    var delCat = e.target.closest('.lh-cms-del-cat');
    if (delCat) { deleteCategory(delCat.dataset.id); return; }

    // Remove question block
    var rmQ = e.target.closest('.lh-rm-question');
    if (rmQ) { var qb = rmQ.closest('.lh-question-block'); if (qb) qb.remove(); return; }

    // Add option to question
    var addOpt = e.target.closest('.lh-add-option');
    if (addOpt) {
      var qBlock = addOpt.closest('.lh-question-block');
      if (qBlock) addOptionRow(qBlock.querySelector('.lh-options-list'), null);
      return;
    }

    // Remove option
    var rmOpt = e.target.closest('.lh-rm-option');
    if (rmOpt) { var row = rmOpt.closest('.lh-option-row'); if (row) row.remove(); return; }
  });

  // wireSearch() called after component is in DOM
  var _searchTimeout = null;
  function wireSearch() {
    var searchEl = document.getElementById('lh-search');
    if (!searchEl || searchEl._wired) return;
    searchEl._wired = true;
    searchEl.addEventListener('input', function() {
      clearTimeout(_searchTimeout);
      var q = searchEl.value.trim();
      if (!q) { loadFeed(); return; }
      _searchTimeout = setTimeout(function() { searchContent(q); }, 350);
    });
    searchEl.addEventListener('keydown', function(e) {
      if (e.key === 'Escape') { searchEl.value = ''; loadFeed(); }
    });
  }

  // ============================================================
  // USER-FACING: FEED, CATEGORIES, CONTENT, QUIZZES
  // ============================================================

  function loadFeed() {
    var feedEl = document.getElementById('lh-feed');
    if (!feedEl) return;
    feedEl.innerHTML = '<p style="text-align:center;color:var(--g400);padding:24px;">Loading...</p>';
    showFeed();

    fetch('/api/learning/feed', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { feedEl.innerHTML = '<p style="text-align:center;color:var(--red);padding:24px;">Failed to load</p>'; return; }
        renderFeed(data.content, feedEl);
      })
      .catch(function() { feedEl.innerHTML = '<p style="text-align:center;color:var(--red);padding:24px;">Connection error</p>'; });
  }

  function loadCategories() {
    fetch('/api/learning/categories', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var bar = document.getElementById('lh-categories');
        if (!bar) return;
        var html = '<button class="lh-cat-pill active" data-slug="all">All</button>';
        data.categories.forEach(function(c) {
          html += '<button class="lh-cat-pill" data-slug="' + esc(c.slug) + '">' + esc(c.name) + '</button>';
        });
        bar.innerHTML = html;
      });
  }

  function loadCategoryContent(slug) {
    var feedEl = document.getElementById('lh-feed');
    if (!feedEl) return;
    feedEl.innerHTML = '<p style="text-align:center;color:var(--g400);padding:24px;">Loading...</p>';
    showFeed();

    fetch('/api/learning/category/' + encodeURIComponent(slug), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { feedEl.innerHTML = '<p style="text-align:center;color:var(--red);padding:24px;">Category not found</p>'; return; }
        renderFeed(data.content, feedEl);
      });
  }

  function searchContent(q) {
    var feedEl = document.getElementById('lh-feed');
    if (!feedEl) return;
    showFeed();
    feedEl.innerHTML =
      '<div style="padding:8px 0 12px;font-size:13px;color:var(--g500);">' +
        '<i class="fas fa-search"></i> Searching for <strong>"' + esc(q) + '"</strong>…' +
      '</div>';

    fetch('/api/learning/search?q=' + encodeURIComponent(q), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { feedEl.innerHTML = '<p style="color:var(--red);padding:12px;">Search failed</p>'; return; }
        var header = '<div style="padding:8px 0 12px;display:flex;align-items:center;justify-content:space-between;">' +
          '<span style="font-size:13px;color:var(--g600);">' +
            (data.content.length > 0
              ? '<strong>' + data.content.length + '</strong> result' + (data.content.length !== 1 ? 's' : '') + ' for <strong>"' + esc(q) + '"</strong>'
              : 'No results for <strong>"' + esc(q) + '"</strong>') +
          '</span>' +
          '<button id="lh-search-clear" style="background:none;border:none;font-size:12px;color:var(--blue);cursor:pointer;padding:0;">Clear search</button>' +
        '</div>';

        if (data.content.length === 0) {
          feedEl.innerHTML = header +
            '<div style="text-align:center;padding:40px;color:var(--g400);">' +
              '<i class="fas fa-search" style="font-size:32px;margin-bottom:12px;display:block;opacity:0.4;"></i>' +
              'Try different keywords or browse by category' +
            '</div>';
        } else {
          var tempEl = document.createElement('div');
          renderFeed(data.content, tempEl);
          feedEl.innerHTML = header + tempEl.innerHTML;
        }

        var clearBtn = document.getElementById('lh-search-clear');
        if (clearBtn) {
          clearBtn.addEventListener('click', function() {
            var s = document.getElementById('lh-search');
            if (s) s.value = '';
            loadFeed();
          });
        }
      })
      .catch(function() { feedEl.innerHTML = '<p style="color:var(--red);padding:12px;">Search error</p>'; });
  }

  function renderFeed(items, feedEl) {
    if (!items || items.length === 0) {
      feedEl.innerHTML = '<div style="text-align:center;padding:40px;color:var(--g400);"><i class="fas fa-book-open" style="font-size:32px;margin-bottom:12px;display:block;"></i>No content yet. Check back soon!</div>';
      return;
    }

    feedEl.innerHTML = items.map(function(item) {
      var typeIcon = item.content_type === 'quiz' ? 'fa-clipboard-question' : item.content_type === 'pearl' ? 'fa-gem' : item.content_type === 'presentation' ? 'fa-presentation-screen' : 'fa-file-alt';
      var typeColor = item.content_type === 'quiz' ? 'var(--amber)' : item.content_type === 'pearl' ? 'var(--purple, #8b5cf6)' : item.content_type === 'presentation' ? '#065f46' : 'var(--blue)';
      var quizBadge = item.question_count > 0 ? '<span class="lh-badge lh-badge-quiz"><i class="fas fa-clipboard-question"></i> ' + item.question_count + ' Q</span>' : '';
      var catBadge = item.category_name ? '<span class="lh-badge">' + esc(item.category_name) + '</span>' : '<span class="lh-badge" style="opacity:0.5;">Uncategorized</span>';
      var date = item.created_at ? new Date(item.created_at).toLocaleDateString() : '';

      return '<div class="lh-feed-item card" data-slug="' + esc(item.slug) + '">' +
        '<div class="lh-feed-item-header">' +
          '<i class="fas ' + typeIcon + '" style="color:' + typeColor + ';font-size:16px;"></i>' +
          '<div style="flex:1;min-width:0;">' +
            '<div class="lh-feed-title">' + esc(item.title) + '</div>' +
            '<div class="lh-feed-meta">' +
              (item.subject ? '<span>' + esc(item.subject) + '</span>' : '') +
              (item.author_name ? '<span>by ' + esc(item.author_name) + '</span>' : '') +
              '<span>' + date + '</span>' +
            '</div>' +
          '</div>' +
          '<div class="lh-feed-badges">' + catBadge + quizBadge + '</div>' +
        '</div>' +
      '</div>';
    }).join('');
  }

  function loadContent(slug) {
    fetch('/api/learning/content/' + encodeURIComponent(slug), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { showToast(data.error || 'Content not found', 'error'); return; }
        currentContent = data.content;
        showViewer(data.content);
      })
      .catch(function() { showToast('Failed to load content', 'error'); });
  }

  function showFeed() {
    currentView = 'feed';
    var feedEl    = document.getElementById('lh-feed');
    var viewerEl  = document.getElementById('lh-viewer');
    var catsEl    = document.getElementById('lh-categories');
    var searchEl  = document.getElementById('lh-search');
    // Use style.display — classList.add('hidden') is overridden by .lh-feed{display:flex}
    // and .lh-category-bar{display:flex} which are defined later in CSS
    if (feedEl)   feedEl.style.display  = 'flex';
    if (viewerEl) viewerEl.style.display = 'none';
    if (catsEl)   catsEl.style.display  = 'flex';
    if (searchEl) { var sc = searchEl.closest('.card'); if (sc) sc.style.display = ''; }
  }

  function showViewer(item) {
    currentView = 'viewer';
    var feedEl    = document.getElementById('lh-feed');
    var viewerEl  = document.getElementById('lh-viewer');
    var catsEl    = document.getElementById('lh-categories');
    var searchEl  = document.getElementById('lh-search');
    if (feedEl)   feedEl.style.display  = 'none';
    if (viewerEl) viewerEl.style.display = 'block';
    if (catsEl)   catsEl.style.display  = 'none';
    if (searchEl) { var sc = searchEl.closest('.card'); if (sc) sc.style.display = 'none'; }

    var titleEl = document.getElementById('lh-viewer-title');
    var metaEl = document.getElementById('lh-viewer-meta');
    var bodyEl = document.getElementById('lh-viewer-body');
    var quizSection = document.getElementById('lh-quiz-section');
    var resultsSection = document.getElementById('lh-quiz-results');
    var progressSection = document.getElementById('lh-progress-section');

    if (titleEl) titleEl.textContent = item.title;
    if (metaEl) {
      var parts = [];
      if (item.category_name) parts.push(item.category_name);
      if (item.subject) parts.push(item.subject);
      if (item.author_name) parts.push('by ' + item.author_name);
      if (item.created_at) parts.push(new Date(item.created_at).toLocaleDateString());
      metaEl.textContent = parts.join(' | ');
    }
    var presViewer = document.getElementById('lh-presentation-viewer');
    var bodyCard   = bodyEl ? bodyEl.closest('.card') : null;

    if (item.content_type === 'presentation') {
      // Hide body card, show presentation card with View Slides button
      if (bodyCard) bodyCard.style.display = 'none';
      if (presViewer) {
        var slideCount = (item.body || '').split(/\n---\n/).length;
        presViewer.className = '';  // remove hidden
        presViewer.innerHTML =
          '<div class="card" style="text-align:center;padding:32px 24px;">' +
            '<div style="font-size:42px;margin-bottom:12px;">📊</div>' +
            '<h3 style="margin:0 0 4px;color:var(--g800);">' + esc(item.title) + '</h3>' +
            '<p style="font-size:13px;color:var(--g500);margin:0 0 20px;">' + slideCount + ' slides' + (item.subject ? ' · ' + esc(item.subject) : '') + '</p>' +
            '<button id="btn-lh-view-slides" class="btn-primary" style="padding:11px 28px;font-size:14px;border-radius:10px;border:none;cursor:pointer;background:var(--blue);color:white;font-weight:600;">' +
              '<i class="fas fa-play-circle"></i> View Slides' +
            '</button>' +
          '</div>';

        // Auto-load and open slides
        document.getElementById('btn-lh-view-slides').addEventListener('click', function() {
          openSlidesFromSlug(item.slug);
        });
        // Open automatically on load
        openSlidesFromSlug(item.slug);
      }
      // Quiz for presentations (optional)
      if (quizSection) {
        if (item.questions && item.questions.length > 0) {
          quizSection.classList.remove('hidden');
          renderQuiz(item.questions);
        } else {
          quizSection.classList.add('hidden');
        }
      }
    } else {
      // Normal content — show body card, hide presentation card
      if (bodyCard) bodyCard.style.display = '';
      if (presViewer) presViewer.className = 'hidden';
      if (bodyEl) bodyEl.innerHTML = sanitizeHtml(item.body || '');

      if (quizSection) {
        if (item.questions && item.questions.length > 0) {
          quizSection.classList.remove('hidden');
          renderQuiz(item.questions);
        } else {
          quizSection.classList.add('hidden');
        }
      }
    }
    if (resultsSection) resultsSection.classList.add('hidden');

    // Progress
    if (progressSection && item.progress && item.progress.length > 0) {
      progressSection.classList.remove('hidden');
      var progHtml = item.progress.map(function(p) {
        var pct = p.total > 0 ? Math.round((p.score / p.total) * 100) : 0;
        var date = new Date(p.completed_at).toLocaleDateString();
        return '<div style="display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px solid var(--g100);">' +
          '<span>' + date + '</span>' +
          '<span style="font-weight:600;color:' + (pct >= 70 ? 'var(--green)' : 'var(--amber)') + ';">' + p.score + '/' + p.total + ' (' + pct + '%)</span>' +
        '</div>';
      }).join('');
      document.getElementById('lh-progress-list').innerHTML = progHtml;
    } else if (progressSection) {
      progressSection.classList.add('hidden');
    }
  }

  function renderQuiz(questions) {
    var container = document.getElementById('lh-quiz-questions');
    var countEl = document.getElementById('lh-quiz-count');
    if (!container) return;
    if (countEl) countEl.textContent = questions.length + ' question' + (questions.length !== 1 ? 's' : '');

    container.innerHTML = questions.map(function(q, idx) {
      var isMulti = q.question_type === 'multi';
      var typeLabel = q.question_type === 'true_false' ? 'True / False'
                    : isMulti ? 'Multiple Select' : 'Single Choice';
      var inputType = isMulti ? 'checkbox' : 'radio';
      var nameAttr = isMulti ? 'lh-qm-' + q.id : 'lh-q-' + q.id;

      var optionsHtml = (q.options || []).map(function(opt) {
        return '<label class="lh-quiz-option">' +
          '<input type="' + inputType + '" name="' + nameAttr + '" value="' + opt.id + '">' +
          '<span>' + sanitizeHtml(opt.option_text) + '</span>' +
        '</label>';
      }).join('');

      var hint = isMulti ? '<div class="lh-quiz-multi-hint">Select all that apply</div>' : '';

      return '<div class="lh-quiz-q" data-qid="' + q.id + '" data-qtype="' + q.question_type + '">' +
        '<div class="lh-quiz-q-header">' +
          '<span class="lh-quiz-q-num">Q' + (idx + 1) + '</span>' +
          '<span class="lh-quiz-q-type">' + typeLabel + '</span>' +
        '</div>' +
        '<p class="lh-quiz-q-text">' + sanitizeHtml(q.question_text) + '</p>' +
        hint +
        '<div class="lh-quiz-options">' + optionsHtml + '</div>' +
      '</div>';
    }).join('');
  }

  function submitQuiz() {
    if (!currentContent || !currentContent.questions) return;

    var answers = [];
    currentContent.questions.forEach(function(q) {
      if (q.question_type === 'multi') {
        var checkedEls = document.querySelectorAll('input[name="lh-qm-' + q.id + '"]:checked');
        var optionIds = [];
        checkedEls.forEach(function(el) { optionIds.push(parseInt(el.value)); });
        answers.push({ questionId: q.id, optionIds: optionIds });
      } else {
        var selected = document.querySelector('input[name="lh-q-' + q.id + '"]:checked');
        answers.push({ questionId: q.id, optionId: selected ? parseInt(selected.value) : null });
      }
    });

    showLoading('Submitting quiz...');

    fetch('/api/learning/submit-quiz', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ contentId: currentContent.id, answers: answers })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      hideLoading();
      if (!data.success) { showToast(data.error || 'Submit failed', 'error'); return; }
      showQuizResults(data);
    })
    .catch(function() { hideLoading(); showToast('Submit failed', 'error'); });
  }

  function showQuizResults(data) {
    var resultsEl = document.getElementById('lh-quiz-results');
    var scoreEl = document.getElementById('lh-quiz-score');
    var explEl = document.getElementById('lh-quiz-explanations');
    if (!resultsEl) return;

    resultsEl.classList.remove('hidden');
    var pct = data.percentage;
    var color = pct >= 80 ? 'var(--green)' : pct >= 50 ? 'var(--amber)' : 'var(--red)';
    if (scoreEl) {
      scoreEl.textContent = data.score + '/' + data.total + ' (' + pct + '%)';
      scoreEl.style.background = color;
      scoreEl.style.color = 'white';
    }

    if (explEl) {
      explEl.innerHTML = data.results.map(function(r, idx) {
        var icon = r.isCorrect ? '<i class="fas fa-check-circle" style="color:var(--green);"></i>' : '<i class="fas fa-times-circle" style="color:var(--red);"></i>';
        var explHtml = '';
        if (!r.isCorrect && r.selectedExplanation) {
          explHtml += '<div class="lh-expl lh-expl-wrong"><strong>Why incorrect:</strong> ' + esc(r.selectedExplanation) + '</div>';
        }
        if (!r.isCorrect) {
          explHtml += '<div class="lh-expl lh-expl-correct"><strong>Correct answer:</strong> ' + esc(r.correctOptionText) + '</div>';
        }
        if (r.generalExplanation) {
          explHtml += '<div class="lh-expl lh-expl-general"><strong>Explanation:</strong> ' + sanitizeHtml(r.generalExplanation) + '</div>';
        }

        return '<div class="lh-result-item">' +
          '<div class="lh-result-header">' + icon + ' <strong>Q' + (idx + 1) + ':</strong> ' + sanitizeHtml(r.questionText) + '</div>' +
          explHtml +
        '</div>';
      }).join('');
    }

    // Highlight correct/incorrect in quiz
    data.results.forEach(function(r) {
      var qDiv = document.querySelector('.lh-quiz-q[data-qid="' + r.questionId + '"]');
      if (!qDiv) return;
      var isMulti = r.questionType === 'multi';
      qDiv.querySelectorAll('.lh-quiz-option').forEach(function(label) {
        var input = label.querySelector('input');
        if (!input) return;
        var optId = parseInt(input.value);
        if (isMulti) {
          var correctIds = r.correctOptionIds || [];
          var selectedIds = r.selectedOptionIds || [];
          if (correctIds.indexOf(optId) !== -1) label.classList.add('lh-opt-correct');
          if (selectedIds.indexOf(optId) !== -1 && correctIds.indexOf(optId) === -1) label.classList.add('lh-opt-wrong');
        } else {
          if (optId === r.correctOptionId) label.classList.add('lh-opt-correct');
          if (optId === r.selectedOptionId && !r.isCorrect) label.classList.add('lh-opt-wrong');
        }
        input.disabled = true;
      });
    });

    // Disable submit button
    var submitBtn = document.getElementById('lh-submit-quiz');
    if (submitBtn) { submitBtn.disabled = true; submitBtn.innerHTML = '<i class="fas fa-check"></i> Submitted'; }

    resultsEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }

  function setActiveCatPill(slug) {
    document.querySelectorAll('.lh-cat-pill').forEach(function(p) {
      p.classList.toggle('active', p.dataset.slug === slug);
    });
  }

  // ============================================================
  // ADMIN CMS
  // ============================================================

  function wireCmsTypeSelect() {
    var typeEl = document.getElementById('lh-cms-edit-type');
    if (typeEl) {
      typeEl.addEventListener('change', function() { toggleEditorMode(typeEl.value); });
    }
  }

  function wireCmsFileInput() {
    var fileInput = document.getElementById('lh-ai-file');
    var fileLabel = document.getElementById('lh-ai-file-label');
    var filesList = document.getElementById('lh-ai-files-list');
    var dropzone  = document.getElementById('lh-ai-dropzone');

    function updateFilesList() {
      if (!fileInput || !fileLabel || !filesList) return;
      var files = fileInput.files;
      if (files.length === 0) {
        fileLabel.textContent = 'Drop files here or click to browse';
        filesList.style.display = 'none';
        filesList.innerHTML = '';
      } else if (files.length === 1) {
        fileLabel.textContent = files[0].name;
        filesList.style.display = 'none';
        filesList.innerHTML = '';
      } else {
        fileLabel.textContent = files.length + ' files selected';
        filesList.style.display = 'block';
        filesList.innerHTML = '<ul style="list-style:none;padding:0;margin:0;font-size:0.9em;">' +
          Array.from(files).map(function(f) {
            return '<li style="padding:2px 0;"><i class="fas fa-file-pdf" style="color:var(--blue);margin-right:4px;"></i>' + f.name + '</li>';
          }).join('') + '</ul>';
      }
    }

    if (fileInput) {
      fileInput.addEventListener('change', updateFilesList);
    }
    if (dropzone) {
      dropzone.addEventListener('dragover', function(e) { e.preventDefault(); dropzone.style.borderColor = 'var(--blue)'; });
      dropzone.addEventListener('dragleave', function() { dropzone.style.borderColor = ''; });
      dropzone.addEventListener('drop', function(e) {
        e.preventDefault();
        dropzone.style.borderColor = '';
        var files = e.dataTransfer.files;
        if (files.length > 0 && fileInput) {
          // Transfer to file input via DataTransfer
          try {
            var dt = new DataTransfer();
            for (var i = 0; i < files.length && i < 10; i++) {
              dt.items.add(files[i]);
            }
            fileInput.files = dt.files;
            updateFilesList();
          } catch(ex) {}
        }
      });
    }
  }

  function loadCms() {
    loadCmsCategories();
    loadCmsContent();
    loadCmsStats();
  }

  // ============================================================
  // AI GENERATE PANEL
  // ============================================================

  var _aiWebdavCurrentPath = '/';
  var _aiWebdavSelectedPath = '';
  var _aiWebdavSelectedName = '';

  function openAiPanel() {
    var panel = document.getElementById('lh-ai-panel');
    if (!panel) return;
    panel.classList.remove('hidden');
    populateAiModelSelect();

    // Sync content type selector with the editor's current type
    var editorType = (document.getElementById('lh-cms-edit-type') || {}).value || 'article';
    var ctype = document.getElementById('lh-ai-ctype');
    if (ctype) ctype.value = editorType;
    updateAiOptions(editorType);

    // Hide WebDAV tab if Nextcloud not configured
    fetch('/api/auth/me', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(d) {
        var tab = document.getElementById('lh-ai-tab-webdav');
        if (tab) tab.style.display = (d.user && d.user.nextcloud_url) ? '' : 'none';
        if (d.user && d.user.webdav_learning_path) _aiWebdavCurrentPath = d.user.webdav_learning_path || '/';
      });

    // Wire ctype change once (use a flag so it doesn't stack on re-opens)
    var ctypeEl = document.getElementById('lh-ai-ctype');
    var toggleEl = document.getElementById('lh-ai-q-toggle');
    if (ctypeEl && !ctypeEl._wired) {
      ctypeEl.addEventListener('change', function() { updateAiOptions(ctypeEl.value); });
      ctypeEl._wired = true;
    }
    if (toggleEl && !toggleEl._wired) {
      toggleEl.addEventListener('change', function() { updateAiOptions((document.getElementById('lh-ai-ctype') || {}).value); });
      toggleEl._wired = true;
    }

    panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
  }

  function updateAiOptions(type) {
    var wordsField  = document.getElementById('lh-ai-words-field');
    var slidesField = document.getElementById('lh-ai-slides-field');
    var quizRow     = document.getElementById('lh-ai-quiz-row');
    var cardTitle   = document.getElementById('lh-ai-quiz-card-title');
    var toggleLabel = document.getElementById('lh-ai-q-toggle-label');
    var toggleCb    = document.getElementById('lh-ai-q-toggle');
    var countWrap   = document.getElementById('lh-ai-q-count-wrap');

    // Use style.display directly — classList.toggle('hidden') doesn't work because
    // .lh-ai-opt-field { display:flex } is defined later in CSS and overrides .hidden
    if (wordsField)  wordsField.style.display  = (type === 'quiz' || type === 'presentation') ? 'none' : 'flex';
    if (slidesField) slidesField.style.display = (type === 'presentation') ? 'flex' : 'none';

    if (type === 'quiz') {
      // Quiz: questions are the whole point — show the card prominently, no toggle needed
      if (quizRow)    quizRow.style.display    = 'block';
      if (cardTitle)  cardTitle.textContent    = 'Quiz Questions';
      if (toggleLabel) toggleLabel.style.display = 'none';
      if (toggleCb)  { toggleCb.checked = true; toggleCb.disabled = true; }
      if (countWrap)  countWrap.style.display  = 'flex';
    } else if (type === 'presentation') {
      // Presentation: optional questions (same as article)
      if (quizRow)    quizRow.style.display    = 'block';
      if (cardTitle)  cardTitle.textContent    = 'Quiz Questions (optional)';
      if (toggleLabel) toggleLabel.style.display = 'flex';
      if (toggleCb)   toggleCb.disabled        = false;
      var checkedP = toggleCb ? toggleCb.checked : false;
      if (countWrap)  countWrap.style.display  = checkedP ? 'flex' : 'none';
    } else {
      // Article / pearl: optional questions via toggle
      if (quizRow)    quizRow.style.display    = 'block';
      if (cardTitle)  cardTitle.textContent    = 'Quiz Questions (optional)';
      if (toggleLabel) toggleLabel.style.display = 'flex';
      if (toggleCb)   toggleCb.disabled        = false;
      var checked = toggleCb ? toggleCb.checked : false;
      if (countWrap)  countWrap.style.display  = checked ? 'flex' : 'none';
    }
  }

  function closeAiPanel() {
    var panel = document.getElementById('lh-ai-panel');
    if (panel) panel.classList.add('hidden');
  }

  function populateAiModelSelect() {
    var sel = document.getElementById('lh-ai-model');
    if (!sel || sel.options.length > 1) return;
    // Copy options from global model select
    var globalSel = document.getElementById('global-model-select');
    if (!globalSel) return;
    sel.innerHTML = globalSel.innerHTML;
    sel.value = globalSel.value;
  }

  function switchAiTab(tabName) {
    document.querySelectorAll('.lh-ai-tab').forEach(function(t) { t.classList.toggle('active', t.dataset.aitab === tabName); });
    document.querySelectorAll('.lh-ai-tabpanel').forEach(function(p) { p.classList.add('hidden'); });
    var tp = document.getElementById('lh-ai-tp-' + tabName);
    if (tp) tp.classList.remove('hidden');
    if (tabName === 'webdav' && !document.querySelector('#lh-ai-webdav-list .lh-webdav-item')) {
      browseWebdav(_aiWebdavCurrentPath);
    }
  }

  // ── WebDAV browser ──────────────────────────────────────────
  function browseWebdav(path) {
    _aiWebdavCurrentPath = path || '/';
    var list = document.getElementById('lh-ai-webdav-list');
    var pathLabel = document.getElementById('lh-ai-webdav-path-label');
    if (list) list.innerHTML = '<div style="padding:12px;text-align:center;color:var(--g400);font-size:13px;"><i class="fas fa-spinner fa-spin"></i> Loading...</div>';
    if (pathLabel) pathLabel.textContent = _aiWebdavCurrentPath;

    fetch('/api/admin/learning/webdav-browse?path=' + encodeURIComponent(_aiWebdavCurrentPath), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { if (list) list.innerHTML = '<div style="padding:12px;color:var(--red);font-size:13px;">' + esc(data.error) + '</div>'; return; }
        if (pathLabel) pathLabel.textContent = data.path;
        renderWebdavList(data);
      })
      .catch(function(err) { if (list) list.innerHTML = '<div style="padding:12px;color:var(--red);font-size:13px;">' + esc(err.message) + '</div>'; });
  }

  function renderWebdavList(data) {
    var list = document.getElementById('lh-ai-webdav-list');
    if (!list) return;

    var html = '';

    // Parent nav
    if (data.path !== '/' && data.path !== data.parentPath) {
      html += '<div class="lh-webdav-item lh-webdav-dir" data-path="' + esc(data.parentPath) + '" data-isdir="1">' +
        '<i class="fas fa-arrow-left" style="color:var(--g400);"></i> <span>..</span></div>';
    }

    if (data.items.length === 0 && html === '') {
      html = '<div style="padding:12px;text-align:center;color:var(--g400);font-size:13px;">Empty folder</div>';
    }

    data.items.forEach(function(item) {
      var icon = item.isDir ? 'fa-folder' : getFileIcon(item.contentType, item.name);
      var iconColor = item.isDir ? 'var(--amber)' : 'var(--blue)';
      var sizeStr = (!item.isDir && item.size) ? ' <span style="color:var(--g400);font-size:11px;">(' + formatBytes(item.size) + ')</span>' : '';
      html += '<div class="lh-webdav-item' + (item.isDir ? ' lh-webdav-dir' : ' lh-webdav-file') + '"' +
        ' data-path="' + esc(item.path) + '" data-name="' + esc(item.name) + '" data-isdir="' + (item.isDir ? '1' : '0') + '">' +
        '<i class="fas ' + icon + '" style="color:' + iconColor + ';width:16px;flex-shrink:0;"></i>' +
        '<span class="lh-webdav-name">' + esc(item.name) + '</span>' + sizeStr +
        '</div>';
    });
    list.innerHTML = html;
  }

  function getFileIcon(mime, name) {
    if (!name) name = '';
    var ext = name.split('.').pop().toLowerCase();
    if (mime && mime.includes('pdf') || ext === 'pdf') return 'fa-file-pdf';
    if (['doc','docx'].includes(ext)) return 'fa-file-word';
    if (['txt','md'].includes(ext)) return 'fa-file-lines';
    if (['html','htm'].includes(ext)) return 'fa-file-code';
    return 'fa-file';
  }

  function formatBytes(bytes) {
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1024*1024) return (bytes/1024).toFixed(0) + ' KB';
    return (bytes/1024/1024).toFixed(1) + ' MB';
  }

  function selectWebdavFile(path, name) {
    _aiWebdavSelectedPath = path;
    _aiWebdavSelectedName = name;
    var browser = document.getElementById('lh-ai-webdav-browser');
    var selDiv  = document.getElementById('lh-ai-webdav-selected');
    var selName = document.getElementById('lh-ai-webdav-selected-name');
    // Hide browser, show selected indicator (use style.display — class="hidden" is overridden by inline styles)
    if (browser) browser.style.display = 'none';
    if (selDiv)  selDiv.style.display  = 'flex';
    if (selName) selName.textContent   = name;
  }

  function deselectWebdavFile() {
    _aiWebdavSelectedPath = '';
    _aiWebdavSelectedName = '';
    var browser = document.getElementById('lh-ai-webdav-browser');
    var selDiv  = document.getElementById('lh-ai-webdav-selected');
    if (selDiv)  selDiv.style.display  = 'none';
    if (browser) browser.style.display = '';
  }

  // ── Generate ────────────────────────────────────────────────
  function runAiGenerate() {
    var activeTab = document.querySelector('.lh-ai-tab.active');
    var tabName = activeTab ? activeTab.dataset.aitab : 'topic';
    var model        = document.getElementById('lh-ai-model') ? document.getElementById('lh-ai-model').value : getSelectedModel();
    var contentType  = document.getElementById('lh-ai-ctype') ? document.getElementById('lh-ai-ctype').value : 'article';
    var refinement   = document.getElementById('lh-ai-refinement') ? document.getElementById('lh-ai-refinement').value.trim() : '';
    var toggleCb     = document.getElementById('lh-ai-q-toggle');
    var generateQs   = contentType === 'quiz' || (toggleCb && toggleCb.checked);
    var questionCount = generateQs ? (document.getElementById('lh-ai-q-count') ? document.getElementById('lh-ai-q-count').value : 5) : 0;
    var wordCount    = document.getElementById('lh-ai-word-count') ? document.getElementById('lh-ai-word-count').value : '';
    var slideCount   = document.getElementById('lh-ai-slide-count') ? document.getElementById('lh-ai-slide-count').value : '';

    var formData = new FormData();
    formData.append('model', model);
    formData.append('questionCount', questionCount);
    formData.append('contentType', contentType);
    if (refinement) formData.append('refinement', refinement);
    if (wordCount)  formData.append('wordCount', wordCount);
    if (slideCount) formData.append('slideCount', slideCount);

    if (tabName === 'topic') {
      var topic = document.getElementById('lh-ai-topic') ? document.getElementById('lh-ai-topic').value.trim() : '';
      if (!topic) { showToast('Describe what you want AI to create', 'error'); return; }
      formData.append('topic', topic);
    } else if (tabName === 'upload') {
      var fileInput = document.getElementById('lh-ai-file');
      if (!fileInput || fileInput.files.length === 0) { showToast('Select at least one file to upload', 'error'); return; }
      for (var i = 0; i < fileInput.files.length; i++) {
        formData.append('files', fileInput.files[i]);
      }
      var uploadCtx = document.getElementById('lh-ai-upload-context');
      if (uploadCtx && uploadCtx.value.trim()) formData.append('topic', uploadCtx.value.trim());
    } else if (tabName === 'webdav') {
      if (!_aiWebdavSelectedPath) { showToast('Select a file from Nextcloud', 'error'); return; }
      formData.append('webdavPath', _aiWebdavSelectedPath);
      var webdavCtx = document.getElementById('lh-ai-webdav-context');
      if (webdavCtx && webdavCtx.value.trim()) formData.append('topic', webdavCtx.value.trim());
    }

    var btn = document.getElementById('btn-lh-ai-generate');
    if (btn) { btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generating...'; }
    showBusy('AI is generating content...');

    // FormData: no Content-Type header (browser sets it with boundary)
    var token = window.AUTH_TOKEN || localStorage.getItem('ped_scribe_token') || '';
    fetch('/api/admin/learning/ai-generate', {
      method: 'POST',
      headers: { 'Authorization': 'Bearer ' + token },
      body: formData
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      hideBusy();
      if (btn) { btn.disabled = false; btn.innerHTML = '<i class="fas fa-wand-magic-sparkles"></i> Generate Content'; }
      if (!data.success) { showToast(data.error || 'Generation failed', 'error'); return; }
      // Presentation returns marpMarkdown directly; others return content{}
      var payload = data.contentType === 'presentation' ? data : data.content;
      applyAiContent(payload, contentType);
      closeAiPanel();
      showToast('Content generated! Review and save.', 'success');
    })
    .catch(function(err) {
      hideBusy();
      if (btn) { btn.disabled = false; btn.innerHTML = '<i class="fas fa-wand-magic-sparkles"></i> Generate Content'; }
      showToast(err.message, 'error');
    });
  }

  function applyAiContent(content, contentType) {
    // Set content type first so toggleEditorMode works correctly
    var typeEl = document.getElementById('lh-cms-edit-type');
    if (typeEl && contentType) { typeEl.value = contentType; toggleEditorMode(contentType); }

    // Presentation: fill Marp textarea
    if (contentType === 'presentation' && content.marpMarkdown) {
      var marpTa = document.getElementById('lh-marp-editor');
      if (marpTa) marpTa.value = content.marpMarkdown;
      // Extract title from first # heading
      var titleMatch = content.marpMarkdown.match(/^#\s+(.+)$/m);
      var titleEl = document.getElementById('lh-cms-edit-title');
      if (titleEl && titleMatch) titleEl.value = titleMatch[1];
      // Fill questions if any were generated alongside slides
      var qContainerP = document.getElementById('lh-cms-questions');
      if (qContainerP) {
        qContainerP.innerHTML = '';
        if (content.questions && Array.isArray(content.questions)) {
          content.questions.forEach(function(q) { addQuestionBlock(q); });
        }
      }
      return;
    }

    // Fill title
    var titleEl2 = document.getElementById('lh-cms-edit-title');
    if (titleEl2 && content.title) titleEl2.value = content.title;

    // Fill subject
    var subjectEl = document.getElementById('lh-cms-edit-subject');
    if (subjectEl && content.subject) subjectEl.value = content.subject;

    // Fill body via Tiptap
    if (_bodyEditor && content.body) _bodyEditor.commands.setContent(content.body);

    // Replace questions
    var qContainer = document.getElementById('lh-cms-questions');
    if (qContainer) {
      qContainer.innerHTML = '';
      if (content.questions && Array.isArray(content.questions)) {
        content.questions.forEach(function(q) { addQuestionBlock(q); });
      }
    }
  }

  function toggleRefineBar(forceShow) {
    var bar   = document.getElementById('lh-ai-refine-bar');
    var input = document.getElementById('lh-ai-refine-input');
    if (!bar) return;
    var show = forceShow !== undefined ? forceShow : bar.style.display === 'none';
    bar.style.display = show ? 'flex' : 'none';
    if (show && input) { input.value = ''; input.focus(); }
  }

  function submitRefineBody() {
    var input = document.getElementById('lh-ai-refine-input');
    var instructions = input ? input.value.trim() : '';
    if (!instructions) { showToast('Enter instructions for refinement', 'error'); return; }

    var currentBody = _bodyEditor ? getTpHTML(_bodyEditor) : '';
    if (!currentBody) { showToast('No body content to refine', 'error'); return; }

    var model = document.getElementById('lh-ai-model') ? document.getElementById('lh-ai-model').value : getSelectedModel();
    toggleRefineBar(false);
    showBusy('Refining content...');

    fetch('/api/admin/learning/ai-refine', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ content: currentBody, instructions: instructions, model: model })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      hideBusy();
      if (!data.success) { showToast(data.error || 'Refine failed', 'error'); return; }
      if (_bodyEditor) _bodyEditor.commands.setContent(data.refined);
      showToast('Body refined!', 'success');
    })
    .catch(function(err) { hideBusy(); showToast(err.message, 'error'); });
  }

  function loadCmsStats() {
    fetch('/api/admin/learning/stats', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var s = data.stats;
        var set = function(id, val) { var el = document.getElementById(id); if (el) el.textContent = val; };
        set('cms-stat-published', s.publishedContent);
        set('cms-stat-drafts', s.totalContent - s.publishedContent);
        set('cms-stat-categories', s.totalCategories);
        set('cms-stat-quizzes', s.totalQuizzes);
        set('cms-stat-attempts', s.totalAttempts);
      });
  }

  function loadCmsCategories() {
    fetch('/api/admin/learning/categories', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var container = document.getElementById('lh-cms-categories');
        if (!container) return;

        if (data.categories.length === 0) {
          container.innerHTML = '<div style="font-size:12px;color:var(--g400);">No categories yet</div>';
        } else {
          container.innerHTML = data.categories.map(function(c) {
            return '<div class="cms-cat-item">' +
              '<span class="cms-cat-name"><i class="fas fa-folder" style="color:var(--amber);margin-right:6px;font-size:11px;"></i>' + esc(c.name) + '</span>' +
              '<span class="cms-cat-count">' + c.content_count + '</span>' +
              '<button class="lh-cms-del-cat" data-id="' + c.id + '" style="border:none;background:none;cursor:pointer;color:var(--g400);font-size:11px;padding:2px;" title="Delete"><i class="fas fa-times"></i></button>' +
            '</div>';
          }).join('');
        }

        // Update category dropdowns (editor + filter)
        var sel = document.getElementById('lh-cms-edit-category');
        if (sel) {
          sel.innerHTML = '<option value="">Uncategorized</option>';
          data.categories.forEach(function(c) {
            sel.innerHTML += '<option value="' + c.id + '">' + esc(c.name) + '</option>';
          });
        }
        var filterSel = document.getElementById('cms-filter-category');
        if (filterSel) {
          filterSel.innerHTML = '<option value="all">All Categories</option>';
          data.categories.forEach(function(c) {
            filterSel.innerHTML += '<option value="' + c.id + '">' + esc(c.name) + '</option>';
          });
        }
      });
  }

  function addCategory() {
    var input = document.getElementById('lh-cms-cat-name');
    if (!input || !input.value.trim()) { showToast('Enter category name', 'error'); return; }

    fetch('/api/admin/learning/categories', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ name: input.value.trim() })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) {
        input.value = '';
        loadCmsCategories();
        loadCategories(); // refresh user-facing pills too
        showToast('Category created', 'success');
      } else showToast(data.error || 'Failed', 'error');
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function deleteCategory(id) {
    if (!window.__confirmDeleteCat) {
      window.__confirmDeleteCat = id;
      showToast('Click delete again to confirm removing this category', 'info');
      setTimeout(function() { window.__confirmDeleteCat = null; }, 4000);
      return;
    }
    window.__confirmDeleteCat = null;
    fetch('/api/admin/learning/categories/' + id, { method: 'DELETE', headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (data.success) { loadCmsCategories(); loadCategories(); showToast('Category deleted', 'info'); }
        else showToast(data.error || 'Failed', 'error');
      });
  }

  function loadCmsContent() {
    var container = document.getElementById('lh-cms-content-list');
    if (!container) return;
    container.innerHTML = '<p style="text-align:center;color:var(--g400);padding:12px;">Loading...</p>';

    fetch('/api/admin/learning/content', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        if (data.content.length === 0) {
          container.innerHTML = '<p style="text-align:center;color:var(--g400);padding:12px;">No content yet. Click "New Content" to create.</p>';
          return;
        }
        window._cmsContentData = data.content;
        renderCmsContentList(data.content);
      });
  }

  function renderCmsContentList(items) {
    var container = document.getElementById('lh-cms-content-list');
    if (!container) return;
    if (!items || items.length === 0) {
      container.innerHTML = '<div style="text-align:center;padding:40px;color:var(--g400);"><i class="fas fa-file-circle-plus" style="font-size:24px;display:block;margin-bottom:8px;"></i>No content yet. Click "New Content" to get started.</div>';
      return;
    }

    container.innerHTML = items.map(function(item) {
      var statusBadge = item.published
        ? '<span class="cms-badge cms-badge-pub">Published</span>'
        : '<span class="cms-badge cms-badge-draft">Draft</span>';
      var typeLabel = item.content_type === 'quiz' ? 'Quiz' : item.content_type === 'pearl' ? 'Pearl' : item.content_type === 'presentation' ? 'Slides' : 'Article';
      var qBadge = item.question_count > 0 ? ' <span style="color:var(--amber);">' + item.question_count + 'Q</span>' : '';
      var date = item.updated_at ? new Date(item.updated_at).toLocaleDateString() : '';

      return '<div class="cms-table-row lh-cms-content-item" data-id="' + item.id + '">' +
        '<span class="cms-col-title">' + esc(item.title) + qBadge + '<br><span class="cms-title-sub">' + esc(item.subject || '') + '</span></span>' +
        '<span class="cms-col-cat">' + esc(item.category_name || 'Uncategorized') + '</span>' +
        '<span class="cms-col-type">' + typeLabel + '</span>' +
        '<span class="cms-col-status">' + statusBadge + '</span>' +
        '<span class="cms-col-date">' + date + '</span>' +
        '<span class="cms-col-actions"><i class="fas fa-pen" style="color:var(--g400);"></i></span>' +
      '</div>';
    }).join('');
  }

  // CMS search & filter
  document.addEventListener('input', function(e) {
    if (e.target.id === 'cms-search') filterCmsContent();
  });
  document.addEventListener('change', function(e) {
    if (e.target.id === 'cms-filter-status' || e.target.id === 'cms-filter-category') filterCmsContent();
  });

  function filterCmsContent() {
    var items = window._cmsContentData || [];
    var search = (document.getElementById('cms-search') || {}).value || '';
    var statusFilter = (document.getElementById('cms-filter-status') || {}).value || 'all';
    var catFilter = (document.getElementById('cms-filter-category') || {}).value || 'all';

    search = search.toLowerCase().trim();
    var filtered = items.filter(function(item) {
      if (search && item.title.toLowerCase().indexOf(search) === -1 && (item.subject || '').toLowerCase().indexOf(search) === -1) return false;
      if (statusFilter === 'published' && !item.published) return false;
      if (statusFilter === 'draft' && item.published) return false;
      if (catFilter !== 'all' && String(item.category_id) !== catFilter) return false;
      return true;
    });
    renderCmsContentList(filtered);
  }

  // ── Tiptap editor helpers ──────────────────────────────────
  var T = window.Tiptap || {};

  function buildTpToolbar(mini, isOption) {
    var btns;
    if (isOption) {
      btns = '<button type="button" class="tp-btn" data-cmd="bold" title="Bold"><i class="fas fa-bold"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="italic" title="Italic"><i class="fas fa-italic"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="link" title="Link"><i class="fas fa-link"></i></button>';
    } else if (mini) {
      btns = '<button type="button" class="tp-btn" data-cmd="bold" title="Bold"><i class="fas fa-bold"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="italic" title="Italic"><i class="fas fa-italic"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="bulletList" title="List"><i class="fas fa-list-ul"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="link" title="Link"><i class="fas fa-link"></i></button>';
    } else {
      btns = '<button type="button" class="tp-btn" data-cmd="bold" title="Bold"><i class="fas fa-bold"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="italic" title="Italic"><i class="fas fa-italic"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="underline" title="Underline"><i class="fas fa-underline"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="strike" title="Strike"><i class="fas fa-strikethrough"></i></button>' +
             '<span class="tp-sep"></span>' +
             '<button type="button" class="tp-btn" data-cmd="h2" title="Heading 2">H2</button>' +
             '<button type="button" class="tp-btn" data-cmd="h3" title="Heading 3">H3</button>' +
             '<span class="tp-sep"></span>' +
             '<button type="button" class="tp-btn" data-cmd="bulletList" title="Bullet List"><i class="fas fa-list-ul"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="orderedList" title="Numbered List"><i class="fas fa-list-ol"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="blockquote" title="Blockquote"><i class="fas fa-quote-left"></i></button>' +
             '<button type="button" class="tp-btn" data-cmd="codeBlock" title="Code"><i class="fas fa-code"></i></button>' +
             '<span class="tp-sep"></span>' +
             '<button type="button" class="tp-btn" data-cmd="link" title="Link"><i class="fas fa-link"></i></button>' +
             '<span class="tp-sep"></span>' +
             '<button type="button" class="tp-btn" data-cmd="clear" title="Clear formatting"><i class="fas fa-remove-format"></i></button>';
    }
    return '<div class="tp-toolbar' + (mini ? ' tp-toolbar-mini' : '') + '">' + btns + '</div>' +
           '<div class="tp-link-bar" style="display:none;">' +
             '<input type="url" class="tp-link-input" placeholder="https://">' +
             '<button type="button" class="tp-link-apply">Apply</button>' +
             '<button type="button" class="tp-link-remove">Remove</button>' +
             '<button type="button" class="tp-link-cancel">✕</button>' +
           '</div>';
  }

  function wireTpToolbar(wrap, editor) {
    var linkBar   = wrap.querySelector('.tp-link-bar');
    var linkInput = wrap.querySelector('.tp-link-input');

    wrap.querySelector('.tp-toolbar').addEventListener('mousedown', function(e) {
      var btn = e.target.closest('.tp-btn[data-cmd]');
      if (!btn) return;
      e.preventDefault();
      var cmd = btn.dataset.cmd;
      switch (cmd) {
        case 'bold':         editor.chain().focus().toggleBold().run(); break;
        case 'italic':       editor.chain().focus().toggleItalic().run(); break;
        case 'underline':    editor.chain().focus().toggleUnderline().run(); break;
        case 'strike':       editor.chain().focus().toggleStrike().run(); break;
        case 'h2':           editor.chain().focus().toggleHeading({ level: 2 }).run(); break;
        case 'h3':           editor.chain().focus().toggleHeading({ level: 3 }).run(); break;
        case 'bulletList':   editor.chain().focus().toggleBulletList().run(); break;
        case 'orderedList':  editor.chain().focus().toggleOrderedList().run(); break;
        case 'blockquote':   editor.chain().focus().toggleBlockquote().run(); break;
        case 'codeBlock':    editor.chain().focus().toggleCodeBlock().run(); break;
        case 'clear':        editor.chain().focus().unsetAllMarks().clearNodes().run(); break;
        case 'link':
          if (linkBar.style.display === 'none') {
            linkInput.value = editor.getAttributes('link').href || '';
            linkBar.style.display = 'flex';
            setTimeout(function() { linkInput.focus(); }, 0);
          } else {
            linkBar.style.display = 'none';
          }
          break;
      }
      updateTpState(wrap, editor);
    });

    wrap.querySelector('.tp-link-apply').addEventListener('mousedown', function(e) {
      e.preventDefault();
      var url = linkInput.value.trim();
      if (url) editor.chain().focus().setLink({ href: url }).run();
      linkBar.style.display = 'none';
    });
    wrap.querySelector('.tp-link-remove').addEventListener('mousedown', function(e) {
      e.preventDefault();
      editor.chain().focus().unsetLink().run();
      linkBar.style.display = 'none';
    });
    wrap.querySelector('.tp-link-cancel').addEventListener('mousedown', function(e) {
      e.preventDefault();
      linkBar.style.display = 'none';
    });
    linkInput.addEventListener('keydown', function(e) {
      if (e.key === 'Enter') { e.preventDefault(); wrap.querySelector('.tp-link-apply').dispatchEvent(new MouseEvent('mousedown')); }
      if (e.key === 'Escape') linkBar.style.display = 'none';
    });
  }

  function updateTpState(wrap, editor) {
    wrap.querySelectorAll('.tp-btn[data-cmd]').forEach(function(btn) {
      var a = false;
      switch (btn.dataset.cmd) {
        case 'bold':        a = editor.isActive('bold'); break;
        case 'italic':      a = editor.isActive('italic'); break;
        case 'underline':   a = editor.isActive('underline'); break;
        case 'strike':      a = editor.isActive('strike'); break;
        case 'h2':          a = editor.isActive('heading', { level: 2 }); break;
        case 'h3':          a = editor.isActive('heading', { level: 3 }); break;
        case 'bulletList':  a = editor.isActive('bulletList'); break;
        case 'orderedList': a = editor.isActive('orderedList'); break;
        case 'blockquote':  a = editor.isActive('blockquote'); break;
        case 'codeBlock':   a = editor.isActive('codeBlock'); break;
        case 'link':        a = editor.isActive('link'); break;
      }
      btn.classList.toggle('active', a);
    });
  }

  function makeTpEditor(wrap, existingHtml, mini, isOption) {
    wrap.innerHTML = buildTpToolbar(mini, isOption) + '<div class="tp-content"></div>';
    var ed = new T.Editor({
      element: wrap.querySelector('.tp-content'),
      extensions: [
        T.StarterKit,
        T.Link.configure({ openOnClick: false, autolink: true }),
        T.Underline
      ],
      content: existingHtml || '',
      onUpdate:          function() { updateTpState(wrap, ed); },
      onSelectionUpdate: function() { updateTpState(wrap, ed); }
    });
    wireTpToolbar(wrap, ed);
    return ed;
  }

  function getTpHTML(editor) {
    if (!editor) return '';
    var html = editor.getHTML();
    return (html === '<p></p>' || html === '') ? '' : html;
  }

  // ── Body editor ────────────────────────────────────────────
  function initBodyEditor() {
    var wrap = document.getElementById('lh-body-editor');
    if (!wrap || _bodyEditor) return;
    _bodyEditor = makeTpEditor(wrap, '', false, false);
  }

  // ── Rich text toggle for questions / options ───────────────
  function toggleRichText(btn) {
    var isActive = btn.classList.contains('active');
    var target = btn.dataset.target;
    var block = btn.closest(target === 'question' ? '.lh-question-block' : '.lh-option-row');
    if (!block) return;

    if (target === 'question') {
      var ta   = block.querySelector('.lh-q-text');
      var wrap = block.querySelector('.lh-q-richtext-wrap');

      if (!isActive) {
        var val = ta ? ta.value : '';
        btn.classList.add('active');
        btn.textContent = 'Plain Text';
        if (ta) ta.style.display = 'none';
        if (!wrap) {
          wrap = document.createElement('div');
          wrap.className = 'lh-q-richtext-wrap';
          ta.parentNode.insertBefore(wrap, ta.nextSibling);
        }
        wrap.style.display = '';
        if (!block._questionEditor) block._questionEditor = makeTpEditor(wrap, val, true, false);
      } else {
        btn.classList.remove('active');
        btn.textContent = 'Rich Text';
        if (block._questionEditor) {
          if (ta) { ta.value = getTpHTML(block._questionEditor); ta.style.display = ''; }
        }
        if (wrap) wrap.style.display = 'none';
      }

    } else {
      var row      = block;
      var optInput = row.querySelector('.lh-opt-text');
      var optWrap  = row.querySelector('.lh-opt-richtext-wrap');

      if (!isActive) {
        var curVal = optInput ? optInput.value : '';
        btn.classList.add('active');
        btn.textContent = 'Plain';
        if (optInput) optInput.style.display = 'none';
        if (!optWrap) {
          optWrap = document.createElement('div');
          optWrap.className = 'lh-opt-richtext-wrap';
          optInput.parentNode.insertBefore(optWrap, optInput.nextSibling);
        }
        optWrap.style.display = '';
        if (!row._optEditor) row._optEditor = makeTpEditor(optWrap, curVal, true, true);
      } else {
        btn.classList.remove('active');
        btn.textContent = 'Rich';
        if (row._optEditor) {
          if (optInput) { optInput.value = getTpHTML(row._optEditor); optInput.style.display = ''; }
        }
        if (optWrap) optWrap.style.display = 'none';
      }
    }
  }

  function getQText(block) {
    var wrap = block.querySelector('.lh-q-richtext-wrap');
    if (block._questionEditor && wrap && wrap.style.display !== 'none') return getTpHTML(block._questionEditor);
    var ta = block.querySelector('.lh-q-text');
    return ta ? ta.value.trim() : '';
  }

  function getOptText(row) {
    var wrap = row.querySelector('.lh-opt-richtext-wrap');
    if (row._optEditor && wrap && wrap.style.display !== 'none') return getTpHTML(row._optEditor);
    var inp = row.querySelector('.lh-opt-text');
    return inp ? inp.value.trim() : '';
  }

  function openEditor(contentId, contentType) {
    var editor = document.getElementById('lh-cms-editor');
    var listView = document.getElementById('cms-list-view');
    if (!editor) return;
    editor.classList.remove('hidden');
    if (listView) listView.classList.add('hidden');

    // Reset
    document.getElementById('lh-cms-edit-id').value = '';
    document.getElementById('lh-cms-edit-title').value = '';
    document.getElementById('lh-cms-edit-subject').value = '';
    document.getElementById('lh-cms-edit-category').value = '';
    document.getElementById('lh-cms-edit-type').value = contentType || 'article';
    document.getElementById('lh-cms-edit-published').value = 'false';
    document.getElementById('lh-cms-questions').innerHTML = '';
    document.getElementById('btn-lh-delete-content').classList.add('hidden');
    hideDeleteConfirm();
    toggleEditorMode(contentType || 'article');
    initBodyEditor();
    if (_bodyEditor) _bodyEditor.commands.clearContent(true);
    var marpTa = document.getElementById('lh-marp-editor');
    if (marpTa) marpTa.value = '';

    // For quiz type, add a starter question
    if (contentType === 'quiz' && !contentId) {
      addQuestionBlock();
    }

    if (!contentId) return;

    // Load existing content
    fetch('/api/admin/learning/content/' + contentId, { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { showToast('Failed to load', 'error'); return; }
        var c = data.content;
        document.getElementById('lh-cms-edit-id').value = c.id;
        document.getElementById('lh-cms-edit-title').value = c.title;
        document.getElementById('lh-cms-edit-subject').value = c.subject || '';
        document.getElementById('lh-cms-edit-category').value = c.category_id || '';
        document.getElementById('lh-cms-edit-type').value = c.content_type || 'article';
        document.getElementById('lh-cms-edit-published').value = c.published ? 'true' : 'false';
        document.getElementById('btn-lh-delete-content').classList.remove('hidden');
        toggleEditorMode(c.content_type || 'article');

        if (c.content_type === 'presentation') {
          var marpEl = document.getElementById('lh-marp-editor');
          if (marpEl) marpEl.value = c.body || '';
        } else {
          if (_bodyEditor) _bodyEditor.commands.setContent(c.body || '');
        }

        // Load questions
        var qContainer = document.getElementById('lh-cms-questions');
        qContainer.innerHTML = '';
        if (c.questions && c.questions.length > 0) {
          c.questions.forEach(function(q) { addQuestionBlock(q); });
        }

        editor.scrollIntoView({ behavior: 'smooth' });
      });
  }

  function toggleEditorMode(contentType) {
    var bodySection = document.getElementById('lh-body-section');
    var marpSection = document.getElementById('lh-marp-section');
    var isPresentation = contentType === 'presentation';
    if (bodySection) bodySection.classList.toggle('hidden', isPresentation);
    if (marpSection) marpSection.classList.toggle('hidden', !isPresentation);
  }

  function closeEditor() {
    var editor = document.getElementById('lh-cms-editor');
    var listView = document.getElementById('cms-list-view');
    if (editor) editor.classList.add('hidden');
    if (listView) listView.classList.remove('hidden');
    hideDeleteConfirm();
  }

  function saveContent() {
    var id = document.getElementById('lh-cms-edit-id').value;
    var title = document.getElementById('lh-cms-edit-title').value.trim();
    var subject = document.getElementById('lh-cms-edit-subject').value.trim();
    var content_type = document.getElementById('lh-cms-edit-type').value;
    var body = content_type === 'presentation'
      ? (document.getElementById('lh-marp-editor') ? document.getElementById('lh-marp-editor').value : '')
      : (_bodyEditor ? getTpHTML(_bodyEditor) : '');
    var category_id = document.getElementById('lh-cms-edit-category').value || null;
    var published = document.getElementById('lh-cms-edit-published').value === 'true';

    if (!title) { showToast('Title required', 'error'); return; }

    // Gather questions with validation
    var questions = [];
    var validationError = false;
    var qBlocks = document.querySelectorAll('#lh-cms-questions .lh-question-block');
    for (var qi = 0; qi < qBlocks.length; qi++) {
      var qBlock = qBlocks[qi];
      var qText = getQText(qBlock);
      if (!qText) continue;
      var qType = qBlock.querySelector('.lh-q-type').value;
      var qExpl = qBlock.querySelector('.lh-q-explanation').value.trim();
      var qId = qBlock.dataset.questionId || null;

      var options = [];
      qBlock.querySelectorAll('.lh-option-row').forEach(function(row) {
        var optText = getOptText(row);
        if (!optText) return;
        options.push({
          option_text: optText,
          is_correct: row.querySelector('.lh-opt-correct').checked,
          explanation: row.querySelector('.lh-opt-expl').value.trim()
        });
      });

      // Validate: must have a correct answer marked
      var hasCorrect = options.some(function(o) { return o.is_correct; });
      if (options.length > 0 && !hasCorrect) {
        showToast('Question "' + qText.substring(0, 50) + '..." needs a correct answer marked', 'error');
        qBlock.style.outline = '2px solid var(--red)';
        qBlock.scrollIntoView({ behavior: 'smooth', block: 'center' });
        validationError = true;
        break;
      }
      qBlock.style.outline = '';

      questions.push({
        id: qId,
        question_text: qText,
        question_type: qType,
        explanation: qExpl,
        options: options
      });
    }
    if (validationError) return;

    var payload = { title: title, body: body, category_id: category_id, subject: subject, content_type: content_type, published: published };

    var method = id ? 'PUT' : 'POST';
    var url = id ? '/api/admin/learning/content/' + id : '/api/admin/learning/content';

    showLoading('Saving...');

    fetch(url, { method: method, headers: getAuthHeaders(), body: JSON.stringify(payload) })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { hideLoading(); showToast(data.error || 'Save failed', 'error'); return; }
        var contentId = id || data.id;

        // Save questions sequentially
        saveQuestions(contentId, questions, 0, function() {
          hideLoading();
          showToast('Content saved', 'success');
          closeEditor();
          loadCmsContent();
          loadCmsStats();
          loaded = false; // force refresh user feed
        });
      })
      .catch(function() { hideLoading(); showToast('Save failed', 'error'); });
  }

  function saveQuestions(contentId, questions, index, callback) {
    if (index >= questions.length) { callback(); return; }

    var q = questions[index];
    var qId = q.id;
    var method, url;

    if (qId) {
      method = 'PUT';
      url = '/api/admin/learning/questions/' + qId;
    } else {
      method = 'POST';
      url = '/api/admin/learning/content/' + contentId + '/questions';
    }

    fetch(url, {
      method: method,
      headers: getAuthHeaders(),
      body: JSON.stringify({
        question_text: q.question_text,
        question_type: q.question_type,
        explanation: q.explanation,
        options: q.options
      })
    })
    .then(function(r) { return r.json(); })
    .then(function() {
      saveQuestions(contentId, questions, index + 1, callback);
    })
    .catch(function() {
      saveQuestions(contentId, questions, index + 1, callback);
    });
  }

  function showDeleteConfirm() {
    var id = document.getElementById('lh-cms-edit-id').value;
    if (!id) return;
    var title     = (document.getElementById('lh-cms-edit-title').value || 'this content').substring(0, 60);
    var ctype     = (document.getElementById('lh-cms-edit-type') || {}).value || 'article';
    var bar       = document.getElementById('lh-delete-confirm-bar');
    var msgEl     = document.getElementById('lh-delete-confirm-msg');
    if (!bar) return;

    // Build wording based on content type
    var typeLabel = { article: 'article', quiz: 'quiz', pearl: 'clinical pearl', presentation: 'presentation' }[ctype] || 'content';
    var consequence = '';
    if (ctype === 'quiz')    consequence = ' All quiz questions will be permanently removed.';
    else if (ctype === 'article' || ctype === 'pearl') consequence = ' Any quiz questions attached to it will also be removed.';
    // Presentation has no questions → no extra wording

    if (msgEl) msgEl.innerHTML = 'Delete the ' + typeLabel + ' <strong>"' + esc(title) + '"</strong>?' + consequence + ' This cannot be undone.';
    bar.classList.remove('hidden');
    bar.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
  }

  function hideDeleteConfirm() {
    var bar = document.getElementById('lh-delete-confirm-bar');
    if (bar) bar.classList.add('hidden');
  }

  function confirmDelete() {
    var id = document.getElementById('lh-cms-edit-id').value;
    if (!id) return;
    hideDeleteConfirm();
    fetch('/api/admin/learning/content/' + id, { method: 'DELETE', headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (data.success) {
          showToast('Content deleted', 'info');
          closeEditor();
          loadCmsContent();
          loadCmsStats();
          loaded = false;
        } else showToast(data.error || 'Failed', 'error');
      });
  }

  // ── Presentation / Marp ──────────────────────────────────────
  function getMarpMarkdown() {
    var ta = document.getElementById('lh-marp-editor');
    return ta ? ta.value.trim() : '';
  }

  // ── Slide preview modal ──────────────────────────────────────
  var _previewSlides = [];
  var _previewIdx = 0;

  // Open slide modal for a published presentation in the user-facing viewer
  function openSlidesFromSlug(slug) {
    showBusy('Loading slides...');
    fetch('/api/learning/content/' + encodeURIComponent(slug) + '/slides', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        hideBusy();
        if (!data.success) { showToast(data.error || 'Could not load slides', 'error'); return; }
        openSlideModal(data.slides, data.css);
      })
      .catch(function(err) { hideBusy(); showToast(err.message, 'error'); });
  }

  function previewSlides() {
    var md = getMarpMarkdown();
    if (!md) { showToast('No slide content yet. Use AI Generate first.', 'info'); return; }

    showBusy('Rendering slides...');

    fetch('/api/admin/learning/preview-slides', {
      method: 'POST', headers: getAuthHeaders(),
      body: JSON.stringify({ markdown: md })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      hideBusy();
      if (!data.success) { showToast(data.error || 'Preview failed', 'error'); return; }
      openSlideModal(data.slides, data.css);
    })
    .catch(function(err) { hideBusy(); showToast(err.message, 'error'); });
  }

  function openSlideModal(slides, css) {
    _previewSlides = slides || [];
    _previewIdx = 0;

    var modal  = document.getElementById('slide-preview-modal');
    var cssEl  = document.getElementById('slide-preview-css');
    var dotsEl = document.getElementById('slide-preview-dots');

    if (!modal) return;

    // Inject Marp CSS once (scoped to preview frame)
    if (cssEl) cssEl.textContent = css || '';

    // Build dot indicators
    if (dotsEl) {
      dotsEl.innerHTML = _previewSlides.map(function(_, i) {
        return '<button class="slide-dot" data-idx="' + i + '" aria-label="Go to slide ' + (i+1) + '"></button>';
      }).join('');
    }

    modal.classList.remove('hidden');
    document.body.style.overflow = 'hidden';
    renderSlide(0);

    // Keyboard navigation
    document._slideKeyHandler = function(e) {
      if (e.key === 'ArrowRight' || e.key === 'ArrowDown') slideStep(1);
      else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') slideStep(-1);
      else if (e.key === 'Escape') closeSlideModal();
    };
    document.addEventListener('keydown', document._slideKeyHandler);

    // Touch/swipe
    var touchStartX = 0;
    modal._touchStart = function(e) { touchStartX = e.touches[0].clientX; };
    modal._touchEnd   = function(e) {
      var dx = e.changedTouches[0].clientX - touchStartX;
      if (Math.abs(dx) > 40) slideStep(dx < 0 ? 1 : -1);
    };
    modal.addEventListener('touchstart', modal._touchStart);
    modal.addEventListener('touchend',   modal._touchEnd);
  }

  function renderSlide(idx) {
    var content = document.getElementById('slide-preview-content');
    var counter = document.getElementById('slide-preview-counter');
    var dots    = document.querySelectorAll('.slide-dot');
    var prev    = document.getElementById('slide-nav-prev');
    var next    = document.getElementById('slide-nav-next');

    if (!content || !_previewSlides.length) return;
    _previewIdx = Math.max(0, Math.min(idx, _previewSlides.length - 1));

    content.innerHTML = _previewSlides[_previewIdx];
    if (counter) counter.textContent = (_previewIdx + 1) + ' / ' + _previewSlides.length;
    if (prev) prev.style.opacity = _previewIdx === 0 ? '0.3' : '1';
    if (next) next.style.opacity = _previewIdx === _previewSlides.length - 1 ? '0.3' : '1';
    dots.forEach(function(d, i) { d.classList.toggle('active', i === _previewIdx); });
  }

  function slideStep(dir) { renderSlide(_previewIdx + dir); }

  function closeSlideModal() {
    var modal = document.getElementById('slide-preview-modal');
    if (modal) modal.classList.add('hidden');
    document.body.style.overflow = '';
    if (document._slideKeyHandler) {
      document.removeEventListener('keydown', document._slideKeyHandler);
      document._slideKeyHandler = null;
    }
  }

  // slide modal nav is wired via the main document click delegation below

  function downloadPptx() {
    var md = getMarpMarkdown();
    if (!md) { showToast('No slide content yet', 'error'); return; }
    var title = document.getElementById('lh-cms-edit-title').value || 'presentation';

    var btn = document.getElementById('btn-lh-download-pptx');
    if (btn) { btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Building...'; }

    fetch('/api/admin/learning/generate-pptx', {
      method: 'POST', headers: getAuthHeaders(),
      body: JSON.stringify({ markdown: md, title: title })
    })
    .then(function(r) {
      if (!r.ok) return r.json().then(function(e) { throw new Error(e.error); });
      return r.blob();
    })
    .then(function(blob) {
      var url = URL.createObjectURL(blob);
      var a = document.createElement('a');
      a.href = url;
      a.download = title.replace(/\s+/g, '-').toLowerCase() + '.pptx';
      a.click();
      URL.revokeObjectURL(url);
      showToast('PPTX downloaded!', 'success');
    })
    .catch(function(err) { showToast(err.message, 'error'); })
    .finally(function() {
      if (btn) { btn.disabled = false; btn.innerHTML = '<i class="fas fa-file-powerpoint"></i> Download PPTX'; }
    });
  }

  function addQuestionBlock(existingQ) {
    var container = document.getElementById('lh-cms-questions');
    if (!container) return;

    var block = document.createElement('div');
    block.className = 'lh-question-block';
    if (existingQ && existingQ.id) block.dataset.questionId = existingQ.id;

    var qNum = container.querySelectorAll('.lh-question-block').length + 1;
    block.innerHTML =
      '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--g200);">' +
        '<div style="display:flex;align-items:center;gap:8px;">' +
          '<span style="background:linear-gradient(135deg,var(--blue),var(--purple));color:white;font-size:12px;font-weight:700;padding:3px 10px;border-radius:6px;">Q' + qNum + '</span>' +
          '<select class="lh-q-type" style="font-size:12px;padding:4px 8px;border:1px solid var(--g300);border-radius:6px;">' +
            '<option value="mcq"' + (existingQ && existingQ.question_type === 'mcq' ? ' selected' : '') + '>Single Choice</option>' +
            '<option value="multi"' + (existingQ && existingQ.question_type === 'multi' ? ' selected' : '') + '>Multiple Select</option>' +
            '<option value="true_false"' + (existingQ && existingQ.question_type === 'true_false' ? ' selected' : '') + '>True / False</option>' +
          '</select>' +
          '<button type="button" class="lh-richtext-btn" data-target="question">Rich Text</button>' +
        '</div>' +
        '<button class="btn-sm btn-ghost lh-rm-question" style="padding:2px 8px;font-size:12px;color:var(--red);"><i class="fas fa-trash"></i></button>' +
      '</div>' +
      '<textarea class="lh-q-text" placeholder="Enter question text..." rows="3" style="width:100%;font-size:14px;font-weight:500;padding:10px;border:1.5px solid var(--g300);border-radius:8px;box-sizing:border-box;margin-bottom:8px;resize:vertical;font-family:inherit;"></textarea>' +
      '<div style="margin-bottom:8px;">' +
        '<label style="font-size:11px;font-weight:600;color:var(--g500);text-transform:uppercase;letter-spacing:0.3px;display:block;margin-bottom:4px;">Answer Options <span style="color:var(--green);">(check the correct answer)</span></label>' +
      '</div>' +
      '<div class="lh-options-list"></div>' +
      '<button class="btn-sm btn-ghost lh-add-option" style="margin-top:6px;font-size:12px;"><i class="fas fa-plus"></i> Add Option</button>' +
      '<div style="margin-top:8px;">' +
        '<label style="font-size:11px;font-weight:600;color:var(--g500);display:block;margin-bottom:3px;">Explanation (shown after answering)</label>' +
        '<textarea class="lh-q-explanation" placeholder="Explain the correct answer..." rows="2" style="width:100%;font-size:12px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;box-sizing:border-box;resize:vertical;font-family:inherit;"></textarea>' +
      '</div>';

    container.appendChild(block);

    // Set textarea values after insertion (can't use value="" attr on textarea)
    block.querySelector('.lh-q-text').value = existingQ ? existingQ.question_text || '' : '';
    block.querySelector('.lh-q-explanation').value = existingQ ? existingQ.explanation || '' : '';

    var optList = block.querySelector('.lh-options-list');
    if (existingQ && existingQ.options && existingQ.options.length > 0) {
      existingQ.options.forEach(function(opt) { addOptionRow(optList, opt); });
    } else if (existingQ && existingQ.question_type === 'true_false') {
      addOptionRow(optList, { option_text: 'True', is_correct: false, explanation: '' });
      addOptionRow(optList, { option_text: 'False', is_correct: false, explanation: '' });
    } else {
      // Add 4 blank MCQ options
      for (var i = 0; i < 4; i++) addOptionRow(optList, null);
    }
  }

  function addOptionRow(container, opt) {
    if (!container) return;
    var row = document.createElement('div');
    row.className = 'lh-option-row';
    row.innerHTML =
      '<label style="display:flex;align-items:center;gap:4px;cursor:pointer;min-width:28px;padding-top:6px;" title="Mark as correct answer">' +
        '<input type="checkbox" class="lh-opt-correct"' + (opt && opt.is_correct ? ' checked' : '') + ' style="accent-color:var(--green);width:16px;height:16px;">' +
      '</label>' +
      '<div style="flex:2;display:flex;flex-direction:column;gap:3px;">' +
        '<input type="text" class="lh-opt-text" placeholder="Option text" style="width:100%;font-size:13px;padding:6px 10px;border:1.5px solid var(--g300);border-radius:6px;box-sizing:border-box;">' +
        '<button type="button" class="lh-richtext-btn" data-target="option" style="align-self:flex-start;">Rich</button>' +
      '</div>' +
      '<input type="text" class="lh-opt-expl" placeholder="Explanation if wrong" value="' + esc(opt ? opt.explanation || '' : '') + '" style="flex:1;font-size:12px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;color:var(--g600);">' +
      '<button class="btn-sm btn-ghost lh-rm-option" style="padding:2px 6px;font-size:12px;color:var(--g400);margin-top:4px;"><i class="fas fa-times"></i></button>';
    container.appendChild(row);
    // Set option text value after insertion (can't use value="" on nested input via innerHTML)
    row.querySelector('.lh-opt-text').value = opt ? opt.option_text || '' : '';
  }

  // ── Helpers ──────────────────────────────────────────────────
  function esc(str) {
    if (!str) return '';
    return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  }

  function sanitizeHtml(html) {
    // DOMPurify is loaded from cdnjs via <script> in index.html. If it somehow
    // fails to load, refuse to render unsafe content rather than falling back
    // to a regex sanitizer (historical bypass risk).
    if (!window.DOMPurify || typeof window.DOMPurify.sanitize !== 'function') {
      console.warn('[learningHub] DOMPurify unavailable — rendering as plain text.');
      var d = document.createElement('div');
      d.textContent = String(html == null ? '' : html);
      return d.innerHTML;
    }
    return window.DOMPurify.sanitize(html, {
      ALLOWED_TAGS: ['p','br','b','strong','i','em','u','s','h1','h2','h3','h4','h5','h6',
        'ul','ol','li','a','blockquote','code','pre','table','thead','tbody','tr','th','td',
        'hr','div','span','sub','sup','dl','dt','dd'],
      ALLOWED_ATTR: ['href','colspan','rowspan','class','target','rel'],
      ADD_ATTR: ['target'],
      FORBID_ATTR: ['style','onerror','onload','onclick','onmouseover'],
      ALLOW_DATA_ATTR: false
    });
  }

})();
