/**
 * Страница /documentation: README и файлы app/docs/*.md через API, рендер Markdown.
 * Зависимости из репозитория: /static/js/vendor/marked.min.js, purify.min.js
 *
 * Автор: Сергей Антропов
 * Сайт: https://devops.org.ru
 */
(function () {
  "use strict";

  var body = document.body;
  var API = (body.dataset.apiBase || "/api/v1").replace(/\/$/, "");
  var DOC_BASE = "/documentation";

  function showErr(el, msg) {
    if (!el) return;
    el.textContent = msg;
    el.classList.remove("hidden");
  }

  function hideErr(el) {
    if (!el) return;
    el.textContent = "";
    el.classList.add("hidden");
  }

  /** Полноэкранный спиннер как на панели (page-loading-overlay в documentation.html). */
  function showDocumentationPageLoadingOverlay() {
    var el = document.getElementById("documentation-page-loading-overlay");
    if (!el) return;
    el.classList.remove("hidden");
    el.setAttribute("aria-busy", "true");
    el.setAttribute("aria-hidden", "false");
    document.body.classList.add("documentation-page-loading");
  }

  function hideDocumentationPageLoadingOverlay() {
    var el = document.getElementById("documentation-page-loading-overlay");
    if (!el) return;
    el.classList.add("hidden");
    el.setAttribute("aria-busy", "false");
    el.setAttribute("aria-hidden", "true");
    document.body.classList.remove("documentation-page-loading");
  }

  function getPathFromLocation() {
    var q = new URLSearchParams(window.location.search || "");
    var p = (q.get("path") || "").trim();
    return p || null;
  }

  function docUrlForPath(relPath) {
    if (!relPath) return DOC_BASE;
    return DOC_BASE + "?path=" + encodeURIComponent(relPath);
  }

  /**
   * Хлебные крошки: Документация → файл (для app/docs/* кроме api_routes — ссылка «app/docs» на api_routes.md).
   */
  function updateBreadcrumbs(docPath) {
    var ol = document.getElementById("doc-breadcrumbs-list");
    if (!ol) return;
    ol.replaceChildren();

    function addLiLink(href, text) {
      var li = document.createElement("li");
      li.className = "doc-breadcrumbs__item";
      var a = document.createElement("a");
      a.href = href;
      a.className = "doc-breadcrumbs__link";
      a.textContent = text;
      li.appendChild(a);
      ol.appendChild(li);
    }

    function addLiCurrent(text) {
      var li = document.createElement("li");
      li.className = "doc-breadcrumbs__item doc-breadcrumbs__item--current";
      li.setAttribute("aria-current", "page");
      li.textContent = text;
      ol.appendChild(li);
    }

    addLiLink(DOC_BASE, "Документация");
    if (!docPath) {
      addLiCurrent("README.md (корень репозитория)");
      return;
    }
    if (docPath.indexOf("app/docs/") === 0) {
      if (docPath === "app/docs/api_routes.md") {
        addLiCurrent("api_routes.md");
      } else {
        addLiLink(docUrlForPath("app/docs/api_routes.md"), "app/docs");
        addLiCurrent(docPath.replace(/^.*\//, ""));
      }
    } else {
      addLiCurrent(docPath);
    }
  }

  /**
   * Внутренняя ссылка на .md под app/docs/: полный путь или относительно текущего файла.
   */
  function resolveInternalMdHref(href, currentDocPath) {
    if (!href) return null;
    var h = href.trim();
    if (h.startsWith("#")) return null;
    if (/^https?:\/\//i.test(h)) return null;
    if (/^mailto:/i.test(h)) return null;

    var abs = h.match(/^(\.\/)?(app\/docs\/[^?#]+\.md)([\?#].*)?$/i);
    if (abs) {
      return { path: abs[2].replace(/\\/g, "/"), tail: abs[3] || "" };
    }
    if (!currentDocPath || currentDocPath.indexOf("app/docs/") !== 0) return null;
    if (h.indexOf("..") >= 0) return null;

    var baseDir = currentDocPath.replace(/[^/]+\.md$/i, "");
    if (!baseDir) baseDir = "app/docs/";
    try {
      var u = new URL(h, "http://doc.local/" + baseDir);
      var pathname = decodeURIComponent(u.pathname.replace(/^\/+/, ""));
      if (pathname.indexOf("..") >= 0) return null;
      if (!pathname.startsWith("app/docs/") || !pathname.endsWith(".md")) return null;
      var tail = (u.hash || "") + (u.search || "");
      return { path: pathname, tail: tail };
    } catch (e) {
      return null;
    }
  }

  function rewriteMdLinks(container, currentDocPath) {
    container.querySelectorAll("a[href]").forEach(function (a) {
      var href = a.getAttribute("href");
      var resolved = resolveInternalMdHref(href, currentDocPath);
      if (!resolved) return;
      a.setAttribute("href", docUrlForPath(resolved.path) + resolved.tail);
      a.classList.add("doc-md-link");
    });
  }

  /**
   * Картинки из app/docs/*.md с src вида images/foo.png → /static/docs-images/foo.png
   * (каталог app/docs/images смонтирован в FastAPI как StaticFiles).
   */
  function rewriteMdImages(container, currentDocPath) {
    if (!currentDocPath || currentDocPath.indexOf("app/docs/") !== 0) return;
    var baseDir = currentDocPath.replace(/[^/]+\.md$/i, "");
    if (!baseDir) return;
    container.querySelectorAll("img[src]").forEach(function (img) {
      var src = (img.getAttribute("src") || "").trim();
      if (!src || /^https?:\/\//i.test(src) || src.startsWith("data:")) return;
      if (src.indexOf("..") >= 0) return;
      if (src.startsWith("/static/docs-images/")) return;
      try {
        var u = new URL(src, "http://doc.local/" + baseDir);
        var pathname = decodeURIComponent(u.pathname.replace(/^\/+/, ""));
        if (pathname.indexOf("..") >= 0) return;
        if (!pathname.startsWith("app/docs/images/")) return;
        var rest = pathname.replace(/^app\/docs\/images\/?/, "");
        if (!rest) return;
        img.setAttribute("src", "/static/docs-images/" + rest);
      } catch (e) {
        /* ignore */
      }
    });
  }

  /** Текст первого H1 в разобранном HTML (для заголовка вкладки). */
  function extractFirstH1Text(root) {
    var h = root.querySelector("h1");
    if (!h) return "";
    return (h.textContent || "").replace(/\s+/g, " ").trim();
  }

  /**
   * Заголовок вкладки: «Документация — <первый H1> — <app_title>» (как в api_routes: заголовок документа).
   */
  function applyDocumentationTabTitle(h1Text) {
    var appTitle = (body.dataset.appTitle || "").trim() || "kind";
    if (h1Text) {
      document.title = "Документация — " + h1Text + " — " + appTitle;
    } else {
      document.title = "Документация — " + appTitle;
    }
  }

  /**
   * До первого H2 — одна карточка; для каждого H2 — одна карточка: заголовок h2 и всё содержимое до следующего H2.
   */
  function sectionizeFromNodes(sourceRoot) {
    var page = document.createElement("div");
    page.className = "readme-doc-page-inner";
    var root = document.createElement("div");
    root.className = "readme-doc-root";
    page.appendChild(root);

    var nodes = Array.prototype.slice.call(sourceRoot.childNodes);
    var i = 0;

    function appendCard(classExtra, chunk) {
      if (!chunk.length) return;
      var card = document.createElement("section");
      card.className = "card readme-section-card markdown-body " + classExtra;
      chunk.forEach(function (n) {
        card.appendChild(n);
      });
      root.appendChild(card);
    }

    function flushIntro() {
      var chunk = [];
      while (i < nodes.length) {
        var n = nodes[i];
        if (n.nodeType === 1 && n.tagName === "H2") break;
        chunk.push(n);
        i++;
      }
      appendCard("readme-section-card--intro", chunk);
    }

    function flushH2Section() {
      if (i >= nodes.length) return;
      var h2 = nodes[i];
      if (h2.nodeType !== 1 || h2.tagName !== "H2") return;
      i++;
      var chunk = [h2];
      while (i < nodes.length) {
        var n = nodes[i];
        if (n.nodeType === 1 && n.tagName === "H2") break;
        chunk.push(n);
        i++;
      }
      appendCard("readme-section-card--block", chunk);
    }

    flushIntro();
    while (i < nodes.length) flushH2Section();
    return page;
  }

  /**
   * Таблицы Markdown с более чем двумя колонками: класс и data-label для мини-карточек при ширине до 480px (CSS).
   * @param {HTMLElement} rootEl
   */
  function markupWideMarkdownTables(rootEl) {
    if (!rootEl || !rootEl.querySelectorAll) return;
    rootEl.querySelectorAll(".markdown-body table").forEach(function (table) {
      var thList = table.querySelectorAll("thead tr th");
      if (!thList.length) return;
      var n = thList.length;
      if (n <= 2) return;
      table.classList.add("markdown-body-table--stack");
      var labels = [];
      for (var i = 0; i < thList.length; i++) {
        labels.push((thList[i].textContent || "").trim());
      }
      var tbody = table.querySelector("tbody");
      if (!tbody) return;
      tbody.querySelectorAll("tr").forEach(function (tr) {
        var tds = tr.querySelectorAll("td");
        for (var j = 0; j < tds.length; j++) {
          if (labels[j]) tds[j].setAttribute("data-label", labels[j]);
        }
      });
    });
  }

  function renderMarkdownToRoot(text, docPath, rootEl, errEl) {
    if (typeof marked === "undefined" || typeof DOMPurify === "undefined") {
      showErr(errEl, "Не загружены скрипты marked или DOMPurify из /static/js/vendor/.");
      applyDocumentationTabTitle("");
      return;
    }

    try {
      try {
        if (marked.defaults && typeof marked.defaults === "object") {
          marked.defaults.breaks = true;
          marked.defaults.gfm = true;
        }
      } catch (e1) {
        /* ignore */
      }
      var rawHtml =
        typeof marked.parse === "function" ? marked.parse(text, { async: false }) : marked(text);

      var temp = document.createElement("div");
      temp.innerHTML = DOMPurify.sanitize(rawHtml);
      rewriteMdLinks(temp, docPath);
      rewriteMdImages(temp, docPath);

      var h1ForTitle = extractFirstH1Text(temp);
      applyDocumentationTabTitle(h1ForTitle);

      while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild);
      var pageInner = sectionizeFromNodes(temp);
      rootEl.appendChild(pageInner);
      markupWideMarkdownTables(rootEl);
      rootEl.removeAttribute("hidden");
    } catch (e2) {
      showErr(errEl, "Ошибка разбора: " + (e2.message || String(e2)));
      applyDocumentationTabTitle("");
    }
  }

  function fetchUrlForPath(docPath) {
    if (!docPath) return API + "/docs/readme";
    return API + "/docs/file?path=" + encodeURIComponent(docPath);
  }

  async function loadDocumentation(docPath, opts) {
    opts = opts || {};
    var push = opts.pushState === true;
    var replace = opts.replaceState === true;

    var rootEl = document.getElementById("readme-doc-root");
    var errEl = document.getElementById("readme-error");
    if (!rootEl) {
      hideDocumentationPageLoadingOverlay();
      return;
    }

    showDocumentationPageLoadingOverlay();
    try {
      hideErr(errEl);
      rootEl.setAttribute("hidden", "hidden");
      while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild);

      updateBreadcrumbs(docPath);

      var url = fetchUrlForPath(docPath);
      var r = await fetch(url, {
        headers: { Accept: "text/markdown, text/plain, */*" },
      });
      var text = await r.text();
      if (!r.ok) {
        var detail = text;
        try {
          var j = JSON.parse(text);
          if (j.detail) detail = typeof j.detail === "string" ? j.detail : JSON.stringify(j.detail);
        } catch (e0) {
          /* raw */
        }
        showErr(errEl, "Не удалось загрузить документ: " + (detail || r.statusText));
        applyDocumentationTabTitle("");
        return;
      }

      renderMarkdownToRoot(text, docPath, rootEl, errEl);

      var newUrl = docUrlForPath(docPath);
      if (push) {
        window.history.pushState({ docPath: docPath }, "", newUrl);
      } else if (replace) {
        window.history.replaceState({ docPath: docPath }, "", newUrl);
      }
    } catch (e) {
      showErr(errEl, "Ошибка: " + (e.message || String(e)));
      applyDocumentationTabTitle("");
    } finally {
      hideDocumentationPageLoadingOverlay();
    }
  }

  function onPopState() {
    loadDocumentation(getPathFromLocation(), {});
  }

  function onRootClick(e) {
    var a = e.target && e.target.closest ? e.target.closest("a.doc-md-link") : null;
    if (!a || !a.getAttribute("href")) return;
    var href = a.getAttribute("href");
    if (href.indexOf(DOC_BASE) !== 0) return;
    e.preventDefault();
    try {
      var u = new URL(href, window.location.origin);
      var p = (u.searchParams.get("path") || "").trim() || null;
      loadDocumentation(p, { pushState: true });
    } catch (e1) {
      loadDocumentation(getPathFromLocation(), { pushState: true });
    }
  }

  function run() {
    var rootEl = document.getElementById("readme-doc-root");
    if (!rootEl) {
      hideDocumentationPageLoadingOverlay();
      return;
    }

    window.addEventListener("popstate", onPopState);
    rootEl.addEventListener("click", onRootClick);

    var initial = getPathFromLocation();
    loadDocumentation(initial, { replaceState: true });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", run);
  } else {
    run();
  }
})();
