/**
 * Docs Comments Widget — Gitea Issues-backed comments for MkDocs pages
 *
 * Loads approved comments from the Express API proxy, supports:
 * - Anonymous comments (with moderation queue)
 * - Gitea OAuth2 login for instant comments
 * - Dark/light theme via MkDocs Material CSS vars
 * - SPA re-init via document$.subscribe()
 */
(function () {
  'use strict';

  // --- Config ---
  function getApiUrl() {
    // env-config.js sets window.PAYMENT_API_URL to the resolved API URL
    return window.PAYMENT_API_URL || 'http://localhost:4000';
  }

  var API_BASE = '';
  var SESSION_KEY = 'docs-comment-gitea-token';
  var USER_KEY = 'docs-comment-gitea-user';
  var STATE_KEY = 'docs-comment-oauth-state';
  var RETURN_KEY = 'docs-comment-return-url';

  // --- Helpers ---

  function escapeHtml(str) {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode(str));
    return div.innerHTML;
  }

  /**
   * Minimal inline markdown: **bold**, *italic*, `code`, [text](url)
   */
  function renderInlineMarkdown(text) {
    var html = escapeHtml(text);
    // Code (backticks)
    html = html.replace(/`([^`]+)`/g, '<code class="dc-inline-code">$1</code>');
    // Bold
    html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
    // Italic
    html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
    // Links
    html = html.replace(
      /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,
      '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
    );
    // Newlines
    html = html.replace(/\n/g, '<br>');
    return html;
  }

  function timeAgo(dateStr) {
    var now = Date.now();
    var then = new Date(dateStr).getTime();
    var diff = Math.floor((now - then) / 1000);

    if (diff < 60) return 'just now';
    if (diff < 3600) return Math.floor(diff / 60) + 'm ago';
    if (diff < 86400) return Math.floor(diff / 3600) + 'h ago';
    if (diff < 2592000) return Math.floor(diff / 86400) + 'd ago';
    return new Date(dateStr).toLocaleDateString();
  }

  function getInitials(name) {
    return name
      .split(/\s+/)
      .map(function (w) { return w[0]; })
      .join('')
      .toUpperCase()
      .slice(0, 2);
  }

  // --- Auth ---

  function getToken() {
    try { return sessionStorage.getItem(SESSION_KEY); } catch { return null; }
  }

  function getUser() {
    try {
      var data = sessionStorage.getItem(USER_KEY);
      return data ? JSON.parse(data) : null;
    } catch { return null; }
  }

  function setAuth(token, user) {
    try {
      sessionStorage.setItem(SESSION_KEY, token);
      sessionStorage.setItem(USER_KEY, JSON.stringify(user));
    } catch { /* sessionStorage unavailable */ }
  }

  function clearAuth() {
    try {
      sessionStorage.removeItem(SESSION_KEY);
      sessionStorage.removeItem(USER_KEY);
    } catch { /* ignore */ }
  }

  // --- API ---

  function fetchComments(pagePath, page, callback) {
    var url = API_BASE + '/api/docs-comments/comments?pagePath=' +
      encodeURIComponent(pagePath) + '&page=' + (page || 1);

    fetch(url)
      .then(function (res) {
        if (!res.ok) throw new Error('HTTP ' + res.status);
        return res.json();
      })
      .then(function (data) { callback(null, data); })
      .catch(function (err) { callback(err); });
  }

  function postAnonymous(payload, callback) {
    fetch(API_BASE + '/api/docs-comments/comments/anonymous', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    })
      .then(function (res) {
        if (!res.ok) return res.json().then(function (d) { throw new Error(d.error || 'Error'); });
        return res.json();
      })
      .then(function (data) { callback(null, data); })
      .catch(function (err) { callback(err); });
  }

  function postAuthenticated(payload, token, callback) {
    fetch(API_BASE + '/api/docs-comments/comments/authenticated', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Gitea-Token': token,
      },
      body: JSON.stringify(payload),
    })
      .then(function (res) {
        if (!res.ok) return res.json().then(function (d) { throw new Error(d.error || 'Error'); });
        return res.json();
      })
      .then(function (data) { callback(null, data); })
      .catch(function (err) { callback(err); });
  }

  function fetchOAuthConfig(callback) {
    fetch(API_BASE + '/api/docs-comments/oauth/config')
      .then(function (res) { return res.json(); })
      .then(function (data) { callback(null, data); })
      .catch(function (err) { callback(err); });
  }

  function exchangeCode(code, redirectUri, callback) {
    fetch(API_BASE + '/api/docs-comments/oauth/exchange', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ code: code, redirectUri: redirectUri }),
    })
      .then(function (res) {
        if (!res.ok) throw new Error('OAuth exchange failed');
        return res.json();
      })
      .then(function (data) { callback(null, data); })
      .catch(function (err) { callback(err); });
  }

  // --- Render ---

  function renderAvatar(comment) {
    if (comment.avatarUrl) {
      return '<img class="dc-avatar" src="' + escapeHtml(comment.avatarUrl) + '" alt="" loading="lazy">';
    }
    return '<span class="dc-avatar dc-avatar--initials">' + escapeHtml(getInitials(comment.authorName)) + '</span>';
  }

  function renderComment(comment) {
    var fullDate = new Date(comment.createdAt).toLocaleString();
    return (
      '<div class="dc-comment">' +
        '<div class="dc-comment__header">' +
          renderAvatar(comment) +
          '<span class="dc-comment__author">' + escapeHtml(comment.authorName) + '</span>' +
          (comment.isAnonymous ? '<span class="dc-comment__badge">Guest</span>' : '') +
          '<time class="dc-comment__time" title="' + escapeHtml(fullDate) + '">' + timeAgo(comment.createdAt) + '</time>' +
        '</div>' +
        '<div class="dc-comment__body">' + renderInlineMarkdown(comment.body) + '</div>' +
      '</div>'
    );
  }

  function renderCommentList(data) {
    if (!data.comments || data.comments.length === 0) {
      return '<p class="dc-empty">No comments yet. Be the first to share your thoughts!</p>';
    }
    return data.comments.map(renderComment).join('');
  }

  function renderForm(pagePath, oauthConfig) {
    var token = getToken();
    var user = getUser();

    if (token && user) {
      // Authenticated form
      return (
        '<div class="dc-form dc-form--authenticated">' +
          '<div class="dc-form__user">' +
            '<img class="dc-avatar" src="' + escapeHtml(user.avatarUrl || '') + '" alt="">' +
            '<span>Commenting as <strong>' + escapeHtml(user.name) + '</strong></span>' +
            '<button class="dc-btn dc-btn--text dc-logout-btn" type="button">Sign out</button>' +
          '</div>' +
          '<textarea class="dc-textarea dc-auth-body" placeholder="Write a comment... (Markdown supported)" rows="3"></textarea>' +
          '<div class="dc-form__actions">' +
            '<button class="dc-btn dc-btn--primary dc-submit-auth" type="button">Post Comment</button>' +
          '</div>' +
        '</div>'
      );
    }

    // Anonymous form with optional OAuth login
    var loginBtn = '';
    if (oauthConfig && oauthConfig.oauthEnabled) {
      loginBtn = '<button class="dc-btn dc-btn--outline dc-login-btn" type="button">Sign in with Gitea</button>';
    }

    return (
      '<div class="dc-form dc-form--anonymous">' +
        '<div class="dc-form__row">' +
          '<input class="dc-input dc-anon-name" type="text" placeholder="Your name *" maxlength="100">' +
          '<input class="dc-input dc-anon-email" type="email" placeholder="Email (optional)" maxlength="255">' +
        '</div>' +
        // Honeypot — hidden from humans
        '<input class="dc-honeypot" type="text" name="website" tabindex="-1" autocomplete="off">' +
        '<textarea class="dc-textarea dc-anon-body" placeholder="Write a comment... (Markdown supported, 10+ characters)" rows="3"></textarea>' +
        '<div class="dc-form__actions">' +
          '<button class="dc-btn dc-btn--primary dc-submit-anon" type="button">Post as Guest</button>' +
          loginBtn +
        '</div>' +
        '<p class="dc-form__note">Guest comments are reviewed before appearing.</p>' +
      '</div>'
    );
  }

  // --- Main Init ---

  function initWidget(container) {
    var pagePath = container.getAttribute('data-page-path') || '';
    if (!pagePath) return;

    API_BASE = getApiUrl();

    container.innerHTML =
      '<div class="dc-widget">' +
        '<h3 class="dc-title">Comments</h3>' +
        '<div class="dc-comments-list dc-loading">Loading comments...</div>' +
        '<div class="dc-form-container"></div>' +
      '</div>';

    var listEl = container.querySelector('.dc-comments-list');
    var formContainer = container.querySelector('.dc-form-container');
    var oauthConfig = null;

    // Load OAuth config + comments in parallel
    fetchOAuthConfig(function (err, config) {
      if (!err && config) oauthConfig = config;
      renderFormSection();
    });

    loadComments(1);

    function loadComments(page) {
      listEl.classList.add('dc-loading');
      listEl.innerHTML = 'Loading comments...';

      fetchComments(pagePath, page, function (err, data) {
        listEl.classList.remove('dc-loading');
        if (err) {
          listEl.innerHTML = '<p class="dc-error">Comments unavailable.</p>';
          return;
        }
        listEl.innerHTML = renderCommentList(data);
      });
    }

    function renderFormSection() {
      formContainer.innerHTML = renderForm(pagePath, oauthConfig);
      bindFormEvents();
    }

    function bindFormEvents() {
      // Anonymous submit
      var submitAnon = formContainer.querySelector('.dc-submit-anon');
      if (submitAnon) {
        submitAnon.addEventListener('click', function () {
          var name = formContainer.querySelector('.dc-anon-name').value.trim();
          var email = formContainer.querySelector('.dc-anon-email').value.trim();
          var body = formContainer.querySelector('.dc-anon-body').value.trim();
          var honeypot = formContainer.querySelector('.dc-honeypot').value;

          if (!name) { showFormError('Please enter your name.'); return; }
          if (body.length < 10) { showFormError('Comment must be at least 10 characters.'); return; }

          submitAnon.disabled = true;
          submitAnon.textContent = 'Posting...';

          postAnonymous(
            { pagePath: pagePath, authorName: name, authorEmail: email || undefined, body: body, website: honeypot },
            function (err) {
              submitAnon.disabled = false;
              submitAnon.textContent = 'Post as Guest';
              if (err) { showFormError(err.message || 'Failed to post comment.'); return; }
              formContainer.querySelector('.dc-anon-body').value = '';
              showFormSuccess('Your comment has been submitted for review.');
            }
          );
        });
      }

      // Authenticated submit
      var submitAuth = formContainer.querySelector('.dc-submit-auth');
      if (submitAuth) {
        submitAuth.addEventListener('click', function () {
          var body = formContainer.querySelector('.dc-auth-body').value.trim();
          var token = getToken();

          if (body.length < 10) { showFormError('Comment must be at least 10 characters.'); return; }
          if (!token) { showFormError('Session expired. Please sign in again.'); clearAuth(); renderFormSection(); return; }

          submitAuth.disabled = true;
          submitAuth.textContent = 'Posting...';

          postAuthenticated(
            { pagePath: pagePath, body: body },
            token,
            function (err) {
              submitAuth.disabled = false;
              submitAuth.textContent = 'Post Comment';
              if (err) {
                if (err.message && err.message.indexOf('401') !== -1) {
                  clearAuth();
                  renderFormSection();
                  showFormError('Session expired. Please sign in again.');
                  return;
                }
                showFormError(err.message || 'Failed to post comment.');
                return;
              }
              formContainer.querySelector('.dc-auth-body').value = '';
              loadComments(1);
            }
          );
        });
      }

      // OAuth login
      var loginBtn = formContainer.querySelector('.dc-login-btn');
      if (loginBtn && oauthConfig && oauthConfig.oauthEnabled) {
        loginBtn.addEventListener('click', function () {
          var state = Math.random().toString(36).slice(2);
          try {
            sessionStorage.setItem(STATE_KEY, state);
            sessionStorage.setItem(RETURN_KEY, window.location.href);
          } catch { /* ignore */ }

          var redirectUri = window.location.origin + '/comments/callback/';
          var url = oauthConfig.authorizeUrl +
            '?client_id=' + encodeURIComponent(oauthConfig.clientId) +
            '&redirect_uri=' + encodeURIComponent(redirectUri) +
            '&response_type=code' +
            '&state=' + encodeURIComponent(state);

          window.location.href = url;
        });
      }

      // Logout
      var logoutBtn = formContainer.querySelector('.dc-logout-btn');
      if (logoutBtn) {
        logoutBtn.addEventListener('click', function () {
          clearAuth();
          renderFormSection();
        });
      }
    }

    function showFormError(msg) {
      removeFormMessages();
      var el = document.createElement('p');
      el.className = 'dc-form-message dc-form-message--error';
      el.textContent = msg;
      formContainer.appendChild(el);
      setTimeout(function () { el.remove(); }, 5000);
    }

    function showFormSuccess(msg) {
      removeFormMessages();
      var el = document.createElement('p');
      el.className = 'dc-form-message dc-form-message--success';
      el.textContent = msg;
      formContainer.appendChild(el);
      setTimeout(function () { el.remove(); }, 5000);
    }

    function removeFormMessages() {
      var msgs = formContainer.querySelectorAll('.dc-form-message');
      for (var i = 0; i < msgs.length; i++) msgs[i].remove();
    }
  }

  // --- OAuth Callback Handler ---

  function handleOAuthCallback() {
    var params = new URLSearchParams(window.location.search);
    var code = params.get('code');
    var state = params.get('state');

    if (!code) return;

    // Verify state
    var savedState;
    try { savedState = sessionStorage.getItem(STATE_KEY); } catch { /* ignore */ }
    if (savedState && state !== savedState) {
      console.warn('[DocsComments] OAuth state mismatch');
      return;
    }

    API_BASE = getApiUrl();
    var redirectUri = window.location.origin + '/comments/callback/';

    exchangeCode(code, redirectUri, function (err, data) {
      if (err || !data || !data.accessToken) {
        console.error('[DocsComments] OAuth exchange failed:', err);
        return;
      }

      setAuth(data.accessToken, data.user);

      // Redirect back to original page
      var returnUrl;
      try { returnUrl = sessionStorage.getItem(RETURN_KEY); } catch { /* ignore */ }
      try {
        sessionStorage.removeItem(STATE_KEY);
        sessionStorage.removeItem(RETURN_KEY);
      } catch { /* ignore */ }

      window.location.href = returnUrl || '/';
    });
  }

  // --- SPA Init ---

  function init() {
    // Check if this is the OAuth callback page
    if (window.location.pathname.indexOf('/comments/callback') !== -1) {
      handleOAuthCallback();
      return;
    }

    var container = document.getElementById('docs-comments');
    if (container) {
      initWidget(container);
    }
  }

  // MkDocs Material SPA navigation support
  if (typeof document$ !== 'undefined') {
    document$.subscribe(function () {
      init();
    });
  } else {
    // Fallback for non-SPA or non-Material builds
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', init);
    } else {
      init();
    }
  }
})();
