// render-skills.js — Skills rendering functions extracted from dashboard.html

let _skillsTab = 'all';
let _skillsPage = 0;
const SKILLS_PER_PAGE = 5;

// Per-runtime tabs that fold native and plugin skills into one bucket — agents
// see "skills my Claude/Copilot install can use" rather than discovery-source
// trivia. Project tabs are added dynamically per configured project.
const SOURCE_META = {
  'claude-code':    { icon: '⚡', label: 'claude',         group: 'claude'  },
  'plugin':         { icon: '🔌', label: 'claude plugin',  group: 'claude'  },
  'copilot':        { icon: '🤖', label: 'copilot',        group: 'copilot' },
  'copilot-plugin': { icon: '🔌', label: 'copilot plugin', group: 'copilot' },
  'agent-skill':    { icon: '🤝', label: 'agent',          group: 'agent'   },
};

function _skillMetaOf(s) {
  if (SOURCE_META[s]) return SOURCE_META[s];
  if (s && s.startsWith('project:')) {
    const name = s.slice('project:'.length);
    return { icon: '📁', label: name, group: name };
  }
  return { icon: '🔧', label: 'unknown', group: 'unknown' };
}

// Inline onclick handlers run in HTML-attr-then-JS context. escHtml alone is
// unsafe (apostrophes survive into the JS string). JSON.stringify produces a
// valid JS literal; HTML-escaping that literal is safe in either context.
function _jsArg(value) {
  return escHtml(JSON.stringify(value == null ? '' : String(value)));
}

function renderSkills(skills) {
  const el = document.getElementById('skills-list');
  const countEl = document.getElementById('skills-count');
  countEl.textContent = skills.length;
  if (!skills.length) {
    el.innerHTML = '<p class="empty">No skills yet. Agents create these when they discover repeatable workflows.</p>';
    return;
  }

  // Group by source
  const groups = {};
  for (const r of skills) {
    const key = _skillMetaOf(r.source).group;
    if (!groups[key]) groups[key] = [];
    groups[key].push(r);
  }
  const groupKeys = Object.keys(groups).sort((a, b) => {
    const order = ['claude', 'copilot', 'agent'];
    const ai = order.indexOf(a), bi = order.indexOf(b);
    if (ai >= 0 && bi >= 0) return ai - bi;
    if (ai >= 0) return -1;
    if (bi >= 0) return 1;
    return a.localeCompare(b);
  });

  // Tab bar
  const tabs = [{ key: 'all', label: 'All (' + skills.length + ')' }];
  for (const k of groupKeys) tabs.push({ key: k, label: k + ' (' + groups[k].length + ')' });

  let html = '<div style="display:flex;gap:4px;margin-bottom:8px;flex-wrap:wrap">';
  for (const t of tabs) {
    const active = _skillsTab === t.key;
    html += '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px;' +
      (active ? 'background:var(--green);color:#fff;border-color:var(--green)' : '') +
      '" onclick="_skillsSelectTab(' + _jsArg(t.key) + ')">' + escHtml(t.label) + '</button>';
  }
  html += '</div>';

  // Note clarifying skill visibility — agents read these on demand. Runtime-
  // native locations (~/.claude/skills, ~/.copilot/skills, plugin skills) are
  // only visible to that runtime. The "agent" tab (~/.agents/skills) is the
  // cross-runtime portable bucket and IS visible to every runtime.
  html += '<div style="font-size:var(--text-xs);color:var(--muted);margin-bottom:8px;line-height:1.4">' +
    'Skills are reference docs agents read on demand — they are not injected wholesale into prompts. ' +
    'Each tab reflects what the matching runtime would see; runtime-native skills are NOT cross-visible. ' +
    'The agent tab (~/.agents/skills) is the cross-runtime portable bucket — visible to every runtime.' +
    '</div>';

  // Filter by tab
  const filtered = _skillsTab === 'all' ? skills : (groups[_skillsTab] || []);

  // Paginate
  const totalPages = Math.ceil(filtered.length / SKILLS_PER_PAGE);
  if (_skillsPage >= totalPages) _skillsPage = Math.max(0, totalPages - 1);
  const page = filtered.slice(_skillsPage * SKILLS_PER_PAGE, (_skillsPage + 1) * SKILLS_PER_PAGE);

  html += '<div style="display:flex;flex-direction:column;gap:6px">';
  for (const r of page) {
    const meta = _skillMetaOf(r.source);
    const autoTag = r.autoGenerated ? '<span style="font-size:var(--text-xs);background:rgba(63,185,80,0.15);color:var(--green);padding:1px 4px;border-radius:3px;margin-left:4px">auto</span>' : '';
    html += '<div class="inbox-item" onclick="openSkill(' + _jsArg(r.file) + ',' + _jsArg(r.source || 'claude-code') + ',' + _jsArg(r.dir || '') + ')" style="border-left-color:var(--green)">' +
      '<div class="inbox-name"><span style="color:var(--green);font-weight:600">' + meta.icon + ' ' + escHtml(r.name) + '</span>' + autoTag +
        '<span style="font-size:var(--text-xs);color:var(--muted);margin-left:auto">' + escHtml(meta.label) + '</span>' +
      '</div>' +
      (r.description ? '<div class="inbox-preview" style="color:var(--text)">' + escHtml(r.description) + '</div>' : '') +
    '</div>';
  }
  html += '</div>';

  // Pagination controls
  if (totalPages > 1) {
    html += '<div style="display:flex;align-items:center;gap:8px;margin-top:6px;justify-content:center">';
    html += '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" ' +
      (_skillsPage === 0 ? 'disabled' : '') +
      ' onclick="_skillsPage--;renderSkills(window._lastSkills)">&laquo;</button>';
    html += '<span style="font-size:var(--text-sm);color:var(--muted)">' + (_skillsPage + 1) + ' / ' + totalPages + '</span>';
    html += '<button class="pr-pager-btn" style="font-size:var(--text-xs);padding:2px 8px" ' +
      (_skillsPage >= totalPages - 1 ? 'disabled' : '') +
      ' onclick="_skillsPage++;renderSkills(window._lastSkills)">&raquo;</button>';
    html += '</div>';
  }

  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() or _jsArg() (fields: skill file/source/dir/name/description/tab labels)
  el.innerHTML = html;
  window._lastSkills = skills;
}

function _skillsSelectTab(key) {
  _skillsTab = key;
  _skillsPage = 0;
  renderSkills(window._lastSkills);
}

function openSkill(file, source, dir) {
  document.getElementById('modal-title').textContent = file;
  document.getElementById('modal-body').innerHTML = '<p style="color:var(--muted)">Loading...</p>';
  document.getElementById('modal').classList.add('open');
  fetch('/api/skill?file=' + encodeURIComponent(file) + '&source=' + encodeURIComponent(source || 'claude-code') + (dir ? '&dir=' + encodeURIComponent(dir) : ''))
    .then(r => r.text())
    .then(content => {
      document.getElementById('modal-title').textContent = file;
      // eslint-disable-next-line no-unsanitized/property -- reason: renderMd() escapes all user-controlled fields before assembling HTML (see dashboard/js/utils.js)
      document.getElementById('modal-body').innerHTML = renderMd(content);
      document.getElementById('modal-body').style.fontFamily = "'Segoe UI', system-ui, sans-serif";
      document.getElementById('modal-body').style.whiteSpace = 'normal';
      _modalDocContext = { title: file, content: content, selection: '' };
      _modalFilePath = (dir ? dir + '/' : 'skills/') + file;
      showModalQa();
    })
    .catch(() => {
      document.getElementById('modal-body').innerHTML = '<p style="color:var(--red)">Failed to load skill.</p>';
    });
}

window.MinionsSkills = { renderSkills, openSkill };
