// dubtapes-rendertest.js
// scope: standalone render test for Dubs cassette rack visuals using live /dubs/playback data when available

(() => {
  const rackMount = document.getElementById('dubtapes-render-block');
  const meta = document.getElementById('dubtapes-render-meta');
  const inspector = document.getElementById('dubtapes-inspector');
  const refreshBtn = document.getElementById('dubtapes-refresh-btn');
  const sampleBtn = document.getElementById('dubtapes-sample-btn');
  const skinBtn = document.getElementById('dubtapes-skin-btn');

  const templateSets = {
    run: ['template-white', 'template-offwhite', 'template-darkgray'],
    error: ['template-lightred', 'template-darkred'],
    enhancement: ['template-lightblue', 'template-darkblue'],
    diagnostic: ['template-peach', 'template-gold']
  };

  const fontSets = ['font-clean', 'font-condensed', 'font-tech', 'font-archive'];
  const fadeSets = ['fade-horizontal', 'fade-center-round', 'fade-diagonal-edge', 'fade-offcenter-round'];
  const nvImageSets = ['/assets/nv1.png', '/assets/nv2.png', '/assets/nv3.png', '/assets/nv4.png'];

  let currentSkin = 'skin-cruise';
  let selectedDubID = '';
  let currentItems = [];

  function stableHash(value) {
    const text = String(value || 'dub');
    let hash = 2166136261;
    for (let i = 0; i < text.length; i += 1) {
      hash ^= text.charCodeAt(i);
      hash = Math.imul(hash, 16777619);
    }
    return Math.abs(hash >>> 0);
  }

  function pick(list, seed, offset = 0) {
    if (!Array.isArray(list) || !list.length) return '';
    return list[(stableHash(`${seed}:${offset}`) % list.length)];
  }

  function normalizeKind(item) {
    const kind = String(item?.kind || '').trim().toLowerCase();
    if (kind === 'error' || String(item?.status || '').toLowerCase() === 'error') return 'error';
    if (kind === 'enhancement') return 'enhancement';
    if (kind === 'diagnostic') return 'diagnostic';
    return 'run';
  }

  function kindClass(kind) {
    if (kind === 'error') return 'is-fail';
    if (kind === 'enhancement') return 'is-enh';
    if (kind === 'diagnostic') return 'is-diag';
    return 'is-run';
  }

  function kindLabel(kind) {
    if (kind === 'error') return 'FAIL';
    if (kind === 'enhancement') return 'ENH';
    if (kind === 'diagnostic') return 'DIAG';
    return 'RUN';
  }

  function manifestText(manifest, names) {
    if (!manifest || typeof manifest !== 'object') return '';
    for (const name of names) {
      const key = Object.keys(manifest).find(k => String(k).toLowerCase() === String(name).toLowerCase());
      const value = key ? String(manifest[key] || '').trim() : '';
      if (value) return value;
    }
    return '';
  }

  function tapeTitle(item) {
    const result = item?.result || {};
    const manifest = item?.manifest || {};
    return String(
      manifestText(manifest, ['Task', 'Enhancement', 'Diagnostic']) ||
      manifestText(manifest, ['Action']) + (manifestText(manifest, ['FilePath']) ? ` ${manifestText(manifest, ['FilePath'])}` : '') ||
      result.summary ||
      result.error ||
      result.message ||
      item?.source ||
      'recorded change'
    ).trim().replace(/\s+/g, ' ').slice(0, 86);
  }

  function escapeHtml(value) {
    return String(value ?? '').replace(/[&<>"']/g, ch => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[ch]));
  }

  function templateFor(item) {
    const kind = normalizeKind(item);
    const seed = item?.dubID || item?.timestamp || tapeTitle(item);
    return {
      kind,
      template: pick(templateSets[kind] || templateSets.run, seed, 1),
      font: pick(fontSets, seed, 2),
      fade: pick(fadeSets, seed, 3),
      nvImage: pick(nvImageSets, seed, 4)
    };
  }

  function renderNvMark(seed, imagePath) {
    const imgSrc = imagePath || '/assets/nv.png';
    return `<span class="DubTapeNv-Eo" aria-hidden="true"><img class="DubTapeNvImage-Eo" src="${imgSrc}" alt="" data-nv-seed="${escapeHtml(seed)}" onerror="this.remove();" /></span>`;
  }
  function renderTape(item, index) {
    const spec = templateFor(item);
    const dubID = String(item?.dubID || `sample-${index}`);
    const label = `${kindLabel(spec.kind)}: ${tapeTitle(item)}`;
    const selected = selectedDubID === dubID ? ' is-selected' : '';
    const classes = [
      'DubTape-Cx',
      kindClass(spec.kind),
      spec.template,
      spec.font,
      spec.fade,
      selected
    ].filter(Boolean).join(' ');
    const nv = spec.kind === 'run' ? renderNvMark(dubID, spec.nvImage) : '';
    return `<button class="${classes}" type="button" data-dub-id="${escapeHtml(dubID)}" data-index="${index}"><span class="DubTapeLabel-Dx">${escapeHtml(label)}</span>${nv}</button>`;
  }

  function renderRack(items) {
    const visibleItems = Array.isArray(items) ? items.slice(0, 34) : [];
    const slots = [`<div class="DubTapeSlot-Cx is-empty" aria-label="empty tape slot"></div>`];
    visibleItems.forEach((item, index) => {
      slots.push(`<div class="DubTapeSlot-Cx">${renderTape(item, index)}</div>`);
    });
    while (slots.length < 18) slots.push(`<div class="DubTapeSlot-Cx is-empty" aria-label="empty tape slot"></div>`);
    rackMount.innerHTML = `<div class="DubTapeRack-Ax ${currentSkin}">${slots.join('')}</div>`;
    rackMount.querySelectorAll('.DubTape-Cx[data-dub-id]').forEach(button => {
      button.addEventListener('click', () => {
        selectedDubID = button.dataset.dubId || '';
        renderRack(currentItems);
        renderInspector(currentItems.find(item => String(item.dubID) === selectedDubID));
      });
    });
  }

  function renderInspector(item) {
    if (!item) {
      inspector.textContent = 'Select a tape to inspect its live data.';
      return;
    }
    const spec = templateFor(item);
    inspector.textContent = JSON.stringify({
      dubID: item.dubID,
      kind: normalizeKind(item),
      status: item.status,
      recorderStatus: item.recorderStatus,
      source: item.source,
      title: tapeTitle(item),
      visual: spec,
      manifest: item.manifest,
      result: item.result
    }, null, 2);
  }

  async function loadLiveDubs() {
    const response = await fetch('/dubs/playback', { cache: 'no-store' });
    const data = await response.json();
    return Array.isArray(data?.tape) ? data.tape : [];
  }

  function sampleItems() {
    const now = Date.now();
    return [
      ['run', 'replacefunction', 'auxsystem.js', 'Trigger AUX startup scan when AI readiness arrives after Verbatim connection'],
      ['diagnostic', 'replaceblock', 'deck.ts', 'Confirm route order before adding static stylesheet paths'],
      ['run', 'replacestring', 'auxmeter.js', 'Limit AUX meter sweep to visible viewport text'],
      ['error', 'typecheck', 'monitorTabDubs.css', 'Property selector collision in Dubs category rules'],
      ['enhancement', 'newfile', 'dubtapes.css', 'Create cassette rack visual language for Dubs'],
      ['run', 'replacefunction', 'monitorProject.js', 'Wire AMP setup resource button'],
      ['diagnostic', 'replacefunction', 'release-check.ts', 'Warn when root CSS files are orphaned'],
      ['run', 'replacestring', 'monitorLaunchGate.js', 'Route legacy signup helper to account portal'],
      ['enhancement', 'newfile', 'dubtapes-rendertest.js', 'Render live Dubs data as cassette spines'],
      ['error', 'capture', 'pathList.ts', 'Compatibility export points at removed Visualizer path'],
      ['run', 'insertbefore', 'monitor.html', 'Load tab CSS on tab activation'],
      ['run', 'newfile', 'monitorTabSettings.css', 'Create Settings tab CSS owner'],
      ['diagnostic', 'shell', 'sysutil/update.ts', 'Confirm update shortcut delegates to release export'],
      ['run', 'replaceblock', 'deck.ts', 'Disconnect backend Visualizer routes'],
      ['enhancement', 'rewritefile', 'monitorTabs.css', 'Reduce shared tab CSS to primitives']
    ].map((row, index) => ({
      dubID: `sample-${index}-${stableHash(row.join(':')).toString(36).slice(0, 6)}`,
      kind: row[0],
      status: row[0] === 'error' ? 'error' : 'done',
      recorderStatus: row[0] === 'error' ? 'NO' : 'RETRIEVED',
      source: row[1],
      project: 'system',
      projectSerial: '00',
      manifest: { Task: row[3], Action: row[1], FilePath: row[2] },
      result: { summary: row[3] },
      timestamp: now - index * 45000
    }));
  }

  async function showLive() {
    try {
      const live = await loadLiveDubs();
      currentItems = live.length ? live : sampleItems();
      selectedDubID = '';
      meta.textContent = live.length
        ? `Rendering ${live.length} live Dubs tape item${live.length === 1 ? '' : 's'} from /dubs/playback.`
        : 'No live Dubs tape items found; rendering sample mix.';
      renderRack(currentItems);
      renderInspector(null);
    } catch (err) {
      currentItems = sampleItems();
      selectedDubID = '';
      meta.textContent = `Live Dubs load failed; rendering sample mix. ${err?.message || err}`;
      renderRack(currentItems);
      renderInspector(null);
    }
  }

  function showSample() {
    currentItems = sampleItems();
    selectedDubID = '';
    meta.textContent = 'Rendering sample Dubs mix.';
    renderRack(currentItems);
    renderInspector(null);
  }

  refreshBtn?.addEventListener('click', () => void showLive());
  sampleBtn?.addEventListener('click', showSample);
  skinBtn?.addEventListener('click', () => {
    currentSkin = currentSkin === 'skin-cruise' ? 'skin-studio' : 'skin-cruise';
    renderRack(currentItems);
  });

  void showLive();
})();
