(function () {
  'use strict';

  const documentPath = document.querySelector('[data-document-path]')?.dataset.documentPath;
  const documentHash = document.querySelector('[data-document-hash]')?.dataset.documentHash;
  const canComment = document.querySelector('[data-document-path]')?.dataset.canComment === 'true';
  const article = document.querySelector('[data-document-path]');
  const workspaceShell = article?.closest('.workspace-shell--document');
  const commentsAsideList = document.querySelector('[data-comments-aside-list]');
  const commentsAsideListMobile = document.querySelector('[data-comments-aside-list-mobile]');
  const stripTrack = document.querySelector('[data-comments-strip-track]');
  const commentsAside = document.querySelector('[data-comments-aside]');
  const commentsSheetToggle = document.querySelector('[data-toggle-comments]');
  const commentsSheetClose = document.querySelector('[data-close-comments]');
  const documentId = documentPath ? 'doc:' + documentPath.replace(/\.md$/, '') : null;
  const commentToggle = document.querySelector('[data-comment-toggle]');
  const commentVisibilityKey = documentId ? `cairnquire:document-comments:${documentId}` : null;

  function readCommentVisibility() {
    if (!commentVisibilityKey) return false;
    try {
      return window.localStorage.getItem(commentVisibilityKey) === 'hidden';
    } catch (err) {
      return false;
    }
  }

  if (!documentId) return;

  function syncVisibility() {
    const hidden = readCommentVisibility();
    if (article) article.classList.toggle('comments-hidden', hidden);
    if (workspaceShell) workspaceShell.classList.toggle('comments-visible', !hidden);
  }

  syncVisibility();

  function commentsHidden() {
    return Boolean(workspaceShell?.classList.contains('comments-visible')) === false;
  }

  function setCommentsHidden(hidden) {
    if (article) article.classList.toggle('comments-hidden', hidden);
    if (workspaceShell) workspaceShell.classList.toggle('comments-visible', !hidden);
    if (commentVisibilityKey) {
      try {
        window.localStorage.setItem(commentVisibilityKey, hidden ? 'hidden' : 'visible');
      } catch (err) {
        // Ignore persistence failures
      }
    }
    if (commentToggle) {
      commentToggle.setAttribute('aria-pressed', hidden ? 'false' : 'true');
      commentToggle.setAttribute('aria-label', hidden ? 'Show comments' : 'Hide comments');
      commentToggle.title = hidden ? 'Show comments' : 'Hide comments';
    }
    if (!hidden) {
      renderCommentsAside();
      updateStripMarkers();
    }
  }

  if (commentToggle) {
    commentToggle.setAttribute('aria-pressed', commentsHidden() ? 'false' : 'true');
    commentToggle.addEventListener('click', () => {
      setCommentsHidden(!commentsHidden());
    });
  }

  function hashParagraph(el) {
    const text = (el.textContent || '').trim();
    if (!text) return null;
    let hash = 0;
    for (let i = 0; i < text.length; i++) {
      const char = text.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash;
    }
    return 'h' + Math.abs(hash).toString(36);
  }

  function addCommentButton(el, hash) {
    const btn = document.createElement('button');
    btn.className = 'comment-anchor-btn';
    btn.type = 'button';
    btn.title = 'Add comment';
    btn.setAttribute('aria-label', 'Add comment');
    btn.innerHTML = `
      <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
        <path d="M21 15a2 2 0 0 1-2 2H8l-5 4V7a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z"></path>
        <path d="M12 8v4"></path>
        <path d="M10 10h4"></path>
      </svg>
      <span class="comment-anchor-count" aria-hidden="true" hidden></span>
      <span class="sr-only">Add comment</span>
    `;
    btn.addEventListener('click', () => promptComment(el, hash));
    el.appendChild(btn);
  }

  function updateCommentButtonState(el, count) {
    const btn = el.querySelector('.comment-anchor-btn');
    if (!btn) return;
    const hasComments = count > 0;
    btn.classList.toggle('comment-anchor-btn--has-comments', hasComments);
    btn.setAttribute('aria-label', hasComments ? `${count} comment${count === 1 ? '' : 's'}` : 'Add comment');
    btn.title = hasComments ? `${count} comment${count === 1 ? '' : 's'}` : 'Add comment';
    const countNode = btn.querySelector('.comment-anchor-count');
    if (countNode) {
      countNode.hidden = !hasComments;
      countNode.textContent = count > 99 ? '99+' : String(count);
    }
  }

  async function promptComment(el, anchorHash) {
    const text = window.prompt('Comment on this paragraph:');
    if (!text || !text.trim()) return;
    try {
      const res = await fetch('/api/comments', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ documentId, versionHash: documentHash, content: text.trim(), anchorHash }),
      });
      if (!res.ok) throw new Error(await res.text());
      await loadCommentsForAnchor(el, anchorHash);
    } catch (err) {
      window.alert('Failed to post comment: ' + err.message);
    }
  }

  async function loadCommentsForAnchor(el, anchorHash) {
    try {
      const res = await fetch(`/api/comments?document_id=${encodeURIComponent(documentId)}&anchor_hash=${encodeURIComponent(anchorHash)}`);
      if (!res.ok) return;
      const data = await res.json();
      renderComments(el, data.comments || []);
    } catch (err) {
      console.error('load comments', err);
    }
  }

  function renderComments(el, comments) {
    const existing = el.querySelector('.comment-list');
    if (existing) existing.remove();

    updateCommentButtonState(el, comments.length);
    el.dataset.hasComments = comments.length > 0 ? 'true' : 'false';

    if (!comments.length) {
      renderCommentsAside();
      updateStripMarkers();
      return;
    }

    const list = document.createElement('div');
    list.className = 'comment-list';
    comments.forEach(c => {
      const item = document.createElement('div');
      item.className = 'comment-item';
      item.innerHTML = `
        <div class="comment-meta"><strong>${escapeHtml(c.authorName || 'Anonymous')}</strong><time>${formatDate(c.createdAt)}</time></div>
        <div class="comment-body">${escapeHtml(c.content)}</div>
      `;
      list.appendChild(item);
    });
    el.appendChild(list);

    renderCommentsAside();
    updateStripMarkers();
  }

  function buildAsideItemFor(el) {
    const comments = [];
    el.querySelectorAll('.comment-item').forEach(item => {
      const meta = item.querySelector('.comment-meta');
      const bodyEl = item.querySelector('.comment-body');
      comments.push({
        authorName: meta?.querySelector('strong')?.textContent || 'Anonymous',
        createdAt: meta?.querySelector('time')?.textContent || '',
        content: bodyEl?.textContent || '',
      });
    });
    if (!comments.length) return null;

    const targetText = (el.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 120);
    const truncated = targetText.length > 120 ? targetText + '…' : targetText;

    const asideItem = document.createElement('div');
    asideItem.className = 'comments-aside-item';
    asideItem.dataset.anchorHash = el.dataset.anchorHash;

    const targetEl = document.createElement('div');
    targetEl.className = 'comments-aside-item__target';
    targetEl.textContent = truncated || 'Commented section';
    targetEl.addEventListener('click', () => {
      el.scrollIntoView({ behavior: 'smooth', block: 'center' });
    });
    asideItem.appendChild(targetEl);

    comments.forEach(c => {
      const commentEl = document.createElement('div');
      commentEl.className = 'comments-aside-item__comment';
      commentEl.innerHTML = `
        <div class="comments-aside-item__meta"><strong>${escapeHtml(c.authorName)}</strong><time>${escapeHtml(c.createdAt)}</time></div>
        <div class="comments-aside-item__body">${escapeHtml(c.content)}</div>
      `;
      asideItem.appendChild(commentEl);
    });

    return asideItem;
  }

  function renderCommentsInto(container) {
    if (!container) return;
    container.innerHTML = '';

    const body = document.querySelector('.markdown-body');
    if (!body) return;

    const commentables = body.querySelectorAll('.commentable[data-has-comments="true"]');
    if (!commentables.length) {
      container.innerHTML = '<p class="document-comments-aside__empty">No comments yet.</p>';
      return;
    }

    commentables.forEach(el => {
      const item = buildAsideItemFor(el);
      if (item) container.appendChild(item);
    });
  }

  function renderCommentsAside() {
    renderCommentsInto(commentsAsideList);
    renderCommentsInto(commentsAsideListMobile);
  }

  function updateStripMarkers() {
    if (!stripTrack) return;
    stripTrack.innerHTML = '';

    const body = document.querySelector('.markdown-body');
    const shell = document.querySelector('.document-shell');
    if (!body || !shell) return;

    const commentables = body.querySelectorAll('.commentable[data-has-comments="true"]');
    const shellRect = shell.getBoundingClientRect();
    const trackHeight = stripTrack.clientHeight;

    commentables.forEach(el => {
      const rect = el.getBoundingClientRect();
      const relativeTop = rect.top - shellRect.top + shell.scrollTop;
      const percent = (relativeTop / shell.scrollHeight) * 100;
      const clamped = Math.max(0, Math.min(95, percent));

      const marker = document.createElement('button');
      marker.className = 'document-comments-strip__marker';
      marker.type = 'button';
      marker.style.top = clamped + '%';
      marker.dataset.anchorHash = el.dataset.anchorHash;
      marker.title = 'Jump to comments';
      marker.addEventListener('click', () => {
        el.scrollIntoView({ behavior: 'smooth', block: 'center' });
        if (commentsHidden()) setCommentsHidden(false);
        // Highlight the corresponding sidebar item
        const asideItem = commentsAsideList?.querySelector(`[data-anchor-hash="${el.dataset.anchorHash}"]`);
        if (asideItem) {
          asideItem.scrollIntoView({ behavior: 'smooth', block: 'center' });
          asideItem.classList.add('is-highlighted');
          setTimeout(() => asideItem.classList.remove('is-highlighted'), 1500);
        }
      });
      stripTrack.appendChild(marker);
    });
  }

  let bidirectionalHoverInitialized = false;
  function initBidirectionalHover() {
    if (bidirectionalHoverInitialized) return;
    bidirectionalHoverInitialized = true;

    const body = document.querySelector('.markdown-body');
    if (!body || !commentsAsideList) return;

    // Body → sidebar + marker
    body.addEventListener('mouseenter', (e) => {
      const el = e.target.closest('.commentable[data-has-comments="true"]');
      if (!el) return;
      const hash = el.dataset.anchorHash;
      const asideItem = commentsAsideList.querySelector(`[data-anchor-hash="${hash}"]`);
      const marker = stripTrack?.querySelector(`[data-anchor-hash="${hash}"]`);
      if (asideItem) asideItem.classList.add('is-highlighted');
      if (marker) marker.classList.add('is-active');
      el.classList.add('is-highlighted');
    }, true);

    body.addEventListener('mouseleave', (e) => {
      const el = e.target.closest('.commentable[data-has-comments="true"]');
      if (!el) return;
      const hash = el.dataset.anchorHash;
      const asideItem = commentsAsideList.querySelector(`[data-anchor-hash="${hash}"]`);
      const marker = stripTrack?.querySelector(`[data-anchor-hash="${hash}"]`);
      if (asideItem) asideItem.classList.remove('is-highlighted');
      if (marker) marker.classList.remove('is-active');
      el.classList.remove('is-highlighted');
    }, true);

    // Sidebar → paragraph + marker (event delegation so it survives re-renders)
    commentsAsideList.addEventListener('mouseenter', (e) => {
      const item = e.target.closest('.comments-aside-item');
      if (!item) return;
      const hash = item.dataset.anchorHash;
      const para = body.querySelector(`[data-anchor-hash="${hash}"]`);
      const marker = stripTrack?.querySelector(`[data-anchor-hash="${hash}"]`);
      if (para) para.classList.add('is-highlighted');
      if (marker) marker.classList.add('is-active');
      item.classList.add('is-highlighted');
    }, true);

    commentsAsideList.addEventListener('mouseleave', (e) => {
      const item = e.target.closest('.comments-aside-item');
      if (!item) return;
      const hash = item.dataset.anchorHash;
      const para = body.querySelector(`[data-anchor-hash="${hash}"]`);
      const marker = stripTrack?.querySelector(`[data-anchor-hash="${hash}"]`);
      if (para) para.classList.remove('is-highlighted');
      if (marker) marker.classList.remove('is-active');
      item.classList.remove('is-highlighted');
    }, true);
  }

  function escapeHtml(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
  }

  function formatDate(iso) {
    const d = new Date(iso);
    return d.toLocaleString();
  }

  function commentsSheetOpen() {
    return commentsAside?.classList.contains('is-open');
  }

  function setCommentsSheetOpen(open) {
    if (!commentsAside) return;
    commentsAside.classList.toggle('is-open', open);
    if (commentsSheetToggle) {
      commentsSheetToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
      commentsSheetToggle.setAttribute('aria-label', open ? 'Hide comments' : 'Show comments');
    }
    if (open) {
      document.body.classList.add('drawer-open');
      renderCommentsAside();
    } else {
      if (!pickerOpen() && !metaOpen()) {
        document.body.classList.remove('drawer-open');
      }
    }
  }

  function pickerOpen() {
    return document.querySelector('[data-picker-drawer]')?.classList.contains('is-open');
  }

  function metaOpen() {
    return document.querySelector('[data-meta-drawer]')?.classList.contains('is-open');
  }

  if (commentsSheetToggle) {
    commentsSheetToggle.addEventListener('click', () => {
      setCommentsSheetOpen(!commentsSheetOpen());
    });
  }

  if (commentsSheetClose) {
    commentsSheetClose.addEventListener('click', () => setCommentsSheetOpen(false));
  }

  function init() {
    const body = document.querySelector('.markdown-body');
    if (!body) return;

    const paragraphs = body.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, blockquote, pre');
    paragraphs.forEach(el => {
      const hash = hashParagraph(el);
      if (!hash) return;
      el.dataset.anchorHash = hash;
      el.classList.add('commentable');
      if (canComment) addCommentButton(el, hash);
      loadCommentsForAnchor(el, hash);
    });

    renderCommentsAside();
    initBidirectionalHover();

    // Update markers on scroll/resize
    const shell = document.querySelector('.document-shell');
    if (shell) {
      shell.addEventListener('scroll', () => requestAnimationFrame(updateStripMarkers));
    }
    window.addEventListener('resize', () => requestAnimationFrame(updateStripMarkers));
    // Initial marker update after layout settles
    setTimeout(updateStripMarkers, 100);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();