/* ==========================================================================
   Architecture Inspector — Script
   ========================================================================== */


/* ── Clipboard utility (works on file:// protocol) ── */

function clipboardWrite(text) {
  if (navigator.clipboard && window.isSecureContext) {
    return navigator.clipboard.writeText(text);
  }
  return new Promise((resolve, reject) => {
    const ta = document.createElement('textarea');
    ta.value = text;
    ta.style.position = 'fixed';
    ta.style.top = '-9999px';
    document.body.appendChild(ta);
    ta.focus();
    ta.select();
    try { document.execCommand('copy') ? resolve() : reject(); }
    catch (e) { reject(e); }
    finally { ta.remove(); }
  });
}


/* ==========================================================================
   Theme
   ========================================================================== */

const THEME_KEY = 'cve-theme';

function toggleTheme() {
  const next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
  document.documentElement.dataset.theme = next;
  localStorage.setItem(THEME_KEY, next);
  renderMermaid();
}


/* ==========================================================================
   Mermaid Diagrams
   ========================================================================== */

const LIGHT_TO_DARK = {
  '#f8f8f8': '#1e1e1e', '#f3f3f3': '#222', '#f0f0f0': '#2a2a2a',
  '#c0c0c0': '#444', '#999': '#666', '#aaa': '#555',
  '#222': '#ddd', '#333': '#c8c8c8', '#444': '#999', '#555': '#999'
};

const LIGHT_THEME_VARS = {
  primaryColor: '#f0f0f0', primaryTextColor: '#333', primaryBorderColor: '#bbb',
  lineColor: '#bbb', secondaryColor: '#fff',
  fontFamily: 'Inter,sans-serif', fontSize: '13px', edgeLabelBackground: '#fafafa'
};

const DARK_THEME_VARS = {
  primaryColor: '#2a2a2a', primaryTextColor: '#ccc', primaryBorderColor: '#444',
  lineColor: '#555', secondaryColor: '#1e1e1e',
  fontFamily: 'Inter,sans-serif', fontSize: '13px', edgeLabelBackground: '#111'
};

const FLOW_OPTS = {
  htmlLabels: true, curve: 'monotoneX',
  padding: 24, nodeSpacing: 40, rankSpacing: 50,
  useMaxWidth: false, wrappingWidth: 300
};

const VERTICAL_FLOW_RE = /\b(?:flowchart|graph)\s+T[DB]\b/i;

/* Collect diagram sources before mermaid processes them */
const diagrams = [];
document.querySelectorAll('pre.mermaid').forEach((pre, i) => {
  const code = pre.textContent;
  const host = document.createElement('div');
  host.className = 'mermaid-host';

  const container = pre.closest('.diagram-container');
  if (container && VERTICAL_FLOW_RE.test(code)) {
    container.classList.add('is-vertical');
  }

  pre.replaceWith(host);
  diagrams.push({ host, code, id: `mmd-${i}` });
});

let generation = 0;

async function renderMermaid() {
  const gen = ++generation;
  const isDark = document.documentElement.dataset.theme === 'dark';

  if (document.fonts?.ready) await document.fonts.ready;

  mermaid.initialize({
    startOnLoad: false,
    theme: 'base',
    securityLevel: 'loose',
    flowchart: FLOW_OPTS,
    themeVariables: isDark ? DARK_THEME_VARS : LIGHT_THEME_VARS
  });

  const colorRe = isDark
    ? new RegExp(Object.keys(LIGHT_TO_DARK).map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'gi')
    : null;

  for (const d of diagrams) {
    if (gen !== generation) return;
    const code = colorRe
      ? d.code.replace(colorRe, m => LIGHT_TO_DARK[m.toLowerCase()] || m)
      : d.code;
    try {
      const { svg } = await mermaid.render(`${d.id}-g${gen}`, code);
      d.host.innerHTML = svg;
      fixSvgBorderRadius(d.host);
    } catch (e) {
      console.warn('Mermaid render error:', e);
    }
  }

  ensureExpandButtons();
}

/* Safari fix: rx/ry in style attribute → SVG attributes */
function fixSvgBorderRadius(container) {
  container.querySelectorAll('[style*="rx:"]').forEach(el => {
    const s = el.getAttribute('style') || '';
    const rxM = s.match(/\brx\s*:\s*([\d.]+)/);
    const ryM = s.match(/\bry\s*:\s*([\d.]+)/);
    if (rxM) el.setAttribute('rx', rxM[1]);
    if (ryM) el.setAttribute('ry', ryM[1]);
  });
}

/* Initial render + font-safe re-render */
renderMermaid();
document.fonts.ready.then(() => setTimeout(renderMermaid, 100));


/* ==========================================================================
   Diagram Expand Modal
   ========================================================================== */

let activeModal = null;
let currentZoom = 1;

function ensureExpandButtons() {
  document.querySelectorAll('.diagram-container').forEach(container => {
    if (container.querySelector('.diagram-expand-btn')) return;
    const btn = document.createElement('button');
    btn.className = 'diagram-expand-btn btn-pill';
    btn.innerHTML = '<i class="ti ti-arrows-maximize"></i> Expand';
    btn.addEventListener('click', () => openDiagramModal(container));
    container.appendChild(btn);
  });
}

function openDiagramModal(container) {
  const svgEl = container.querySelector('svg');
  if (!svgEl) return;

  closeDiagramModal();
  currentZoom = 1;

  const modal = document.createElement('div');
  modal.className = 'diagram-modal';
  modal.innerHTML = `
    <div class="diagram-modal__panel">
      <div class="diagram-modal__toolbar">
        <div class="diagram-modal__zoom-controls">
          <button class="btn-pill zm-out" title="Zoom out">\u2212</button>
          <span class="diagram-modal__zoom-pct">100%</span>
          <button class="btn-pill zm-in" title="Zoom in">+</button>
          <button class="btn-pill zm-reset" title="Reset zoom">\u21BA</button>
        </div>
        <button class="diagram-modal__close" title="Close (Esc)">\u2715</button>
      </div>
      <div class="diagram-modal__viewport">
        <div class="diagram-modal__canvas"></div>
      </div>
    </div>`;

  const canvas = modal.querySelector('.diagram-modal__canvas');
  canvas.appendChild(svgEl.cloneNode(true));

  const pctLabel = modal.querySelector('.diagram-modal__zoom-pct');

  function setZoom(z) {
    currentZoom = Math.max(0.25, Math.min(4, z));
    canvas.style.transform = `scale(${currentZoom})`;
    pctLabel.textContent = Math.round(currentZoom * 100) + '%';
  }

  modal.querySelector('.zm-in').addEventListener('click', () => setZoom(currentZoom + 0.2));
  modal.querySelector('.zm-out').addEventListener('click', () => setZoom(currentZoom - 0.2));
  modal.querySelector('.zm-reset').addEventListener('click', () => setZoom(1));
  modal.querySelector('.diagram-modal__close').addEventListener('click', closeDiagramModal);
  modal.addEventListener('click', e => { if (e.target === modal) closeDiagramModal(); });

  bindMousePan(modal.querySelector('.diagram-modal__viewport'));

  document.body.appendChild(modal);
  document.body.classList.add('has-diagram-modal');
  activeModal = modal;
  requestAnimationFrame(() => modal.classList.add('is-visible'));
}

function closeDiagramModal() {
  if (!activeModal) return;
  const ref = activeModal;
  activeModal = null;
  ref.classList.remove('is-visible');
  ref.addEventListener('transitionend', () => {
    ref.remove();
    document.body.classList.remove('has-diagram-modal');
  }, { once: true });
}

function bindMousePan(viewport) {
  let active = false, startX, startY, scrollL, scrollT;

  viewport.addEventListener('mousedown', e => {
    if (e.button !== 0) return;
    active = true;
    viewport.classList.add('is-dragging');
    startX = e.clientX;
    startY = e.clientY;
    scrollL = viewport.scrollLeft;
    scrollT = viewport.scrollTop;
  });

  window.addEventListener('mousemove', e => {
    if (!active) return;
    viewport.scrollLeft = scrollL - (e.clientX - startX);
    viewport.scrollTop = scrollT - (e.clientY - startY);
  });

  window.addEventListener('mouseup', () => {
    if (!active) return;
    active = false;
    viewport.classList.remove('is-dragging');
  });
}

document.addEventListener('keydown', e => {
  if (e.key === 'Escape' && activeModal) closeDiagramModal();
});


/* ==========================================================================
   Accordion
   ========================================================================== */

function toggleAccordion(summaryEl) {
  const item = summaryEl.parentElement;
  const collapse = item.querySelector('.acc-collapse');
  const isOpen = item.classList.contains('is-open');

  if (isOpen) {
    collapse.style.maxHeight = collapse.scrollHeight + 'px';
    requestAnimationFrame(() => {
      collapse.style.maxHeight = '0px';
      collapse.style.opacity = '0';
    });
    item.classList.remove('is-open');
  } else {
    item.classList.add('is-open');
    collapse.style.maxHeight = collapse.scrollHeight + 'px';
    collapse.style.opacity = '1';
    collapse.addEventListener('transitionend', function handler() {
      if (item.classList.contains('is-open')) collapse.style.maxHeight = 'none';
      collapse.removeEventListener('transitionend', handler);
    });
  }
}

/* Hydrate items that start open */
document.querySelectorAll('.acc-item.is-open .acc-collapse').forEach(collapse => {
  collapse.style.maxHeight = 'none';
  collapse.style.opacity = '1';
});


/* ==========================================================================
   Staggered Reveal
   ========================================================================== */

(() => {
  const INITIAL_DELAY = 300;
  const STAGGER = 150;
  const CAP = 20;

  const page = document.querySelector('.page');
  if (!page) return;

  const elements = Array.from(page.children);
  elements.forEach(el => el.classList.add('reveal'));

  setTimeout(() => {
    elements.forEach((el, i) => {
      const delay = Math.min(i, CAP) * STAGGER;
      setTimeout(() => el.classList.add('visible'), delay);
    });
  }, INITIAL_DELAY);
})();


/* ==========================================================================
   Copy All as Markdown
   ========================================================================== */

function copyAllAsMarkdown(btn) {
  const page = document.querySelector('.page');
  if (!page) return;

  const lines = [];

  /* Cover */
  const title = page.querySelector('.cover h1');
  if (title) lines.push('# ' + title.textContent.trim(), '');
  const sub = page.querySelector('.cover-sub');
  if (sub) lines.push(sub.textContent.trim(), '');

  /* Sections */
  page.querySelectorAll('.section').forEach(section => {
    const titleEl = section.querySelector('.section-title');
    if (titleEl) lines.push('## ' + titleEl.textContent.trim(), '');

    const intro = section.querySelector('.section-intro');
    if (intro) lines.push(intro.textContent.trim(), '');

    /* About (rich-text prose) */
    const about = section.querySelector('.about');
    if (about) {
      about.querySelectorAll('p').forEach(p => {
        lines.push(p.textContent.trim(), '');
      });
    }

    /* File tree */
    const ft = section.querySelector('.ft');
    if (ft) { serializeFileTree(ft, 0, lines); lines.push(''); }

    /* Diagram source */
    const dc = section.querySelector('.diagram-container');
    if (dc) {
      const idx = Array.from(document.querySelectorAll('.diagram-container')).indexOf(dc);
      if (idx >= 0 && diagrams[idx]) {
        lines.push('```mermaid', diagrams[idx].code.trim(), '```', '');
      }
    }

    /* Tool cards */
    section.querySelectorAll('.tool-card').forEach(card => {
      const name = card.querySelector('.tool-top');
      if (name) lines.push('### ' + name.textContent.trim(), '');

      const desc = card.querySelector('.tool-desc');
      if (desc) lines.push(desc.textContent.trim(), '');

      const cmd = card.querySelector('.tool-cmd');
      if (cmd) lines.push('```', cmd.textContent.trim(), '```', '');

      const deps = card.querySelector('.tool-deps');
      if (deps) lines.push('**Dependencies:** ' + deps.textContent.trim(), '');

      const table = card.querySelector('.tool-params table');
      if (table) { serializeTable(table, lines); lines.push(''); }
    });

    /* Accordion items */
    const accordion = section.querySelector('.accordion');
    if (accordion) {
      accordion.querySelectorAll('.acc-item').forEach(item => {
        const summary = item.querySelector('.acc-summary');
        if (!summary) return;

        const summaryText = Array.from(summary.childNodes)
          .filter(n => !n.classList || !n.classList.contains('acc-icon'))
          .map(n => n.textContent).join('').trim();
        lines.push('### ' + summaryText, '');

        const body = item.querySelector('.acc-body');
        if (!body) return;

        const steps = body.querySelectorAll('.wf-step');
        if (steps.length) {
          steps.forEach(step => {
            const num = step.querySelector('.wf-num');
            const full = step.textContent.trim();
            const numStr = num ? num.textContent.trim() : '';
            const text = numStr ? full.replace(numStr, '').trim() : full;
            lines.push((numStr ? numStr + '. ' : '- ') + text);
          });
          lines.push('');
        } else {
          const detail = body.querySelector('.acc-detail');
          const clone = body.cloneNode(true);
          const detailClone = clone.querySelector('.acc-detail');
          if (detailClone) detailClone.remove();
          const mainText = clone.textContent.trim();
          if (mainText) lines.push(mainText, '');
          if (detail) lines.push('> ' + detail.textContent.trim(), '');
        }
      });
    }
  });

  const md = lines.join('\n').replace(/\n{3,}/g, '\n\n').trim();

  clipboardWrite(md).then(() => {
    btn.innerHTML = '<i class="ti ti-check"></i> Copied';
    btn.classList.add('is-copied');
    setTimeout(() => {
      btn.innerHTML = '<i class="ti ti-copy"></i> Copy';
      btn.classList.remove('is-copied');
    }, 2000);
  });
}

/* ── Markdown serializers ── */

function serializeFileTree(ul, depth, lines) {
  for (const li of ul.children) {
    if (li.tagName !== 'LI') continue;
    const nameEl = li.querySelector(':scope > .n');
    const descEl = li.querySelector(':scope > .d');
    const name = nameEl ? nameEl.textContent.trim() : '';
    const desc = descEl ? ' — ' + descEl.textContent.trim() : '';
    if (name) lines.push('  '.repeat(depth) + '- ' + name + desc);

    const nested = li.querySelector(':scope > ul');
    if (nested) serializeFileTree(nested, depth + 1, lines);
  }
}

function serializeTable(table, lines) {
  const rows = table.querySelectorAll('tr');
  if (!rows.length) return;

  const headers = [];
  const firstCells = rows[0].querySelectorAll('th');
  (firstCells.length ? firstCells : rows[0].querySelectorAll('td'))
    .forEach(cell => headers.push(cell.textContent.trim()));

  lines.push('| ' + headers.join(' | ') + ' |');
  lines.push('| ' + headers.map(() => '---').join(' | ') + ' |');

  const startIdx = firstCells.length ? 1 : 0;
  for (let i = startIdx; i < rows.length; i++) {
    const cells = [];
    rows[i].querySelectorAll('td').forEach(td => cells.push(td.textContent.trim()));
    if (cells.length) lines.push('| ' + cells.join(' | ') + ' |');
  }
}
