<script>
// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//
// ifcurl — inject "View in 3D" button on .ifc file view and history pages.
//
// Deploy to: /etc/forgejo/templates/custom/footer.tmpl
//
// Uses commit-hash hrefs (always unambiguous) to construct ifc:// URLs.
(function () {
  "use strict";

  var VIEWER_BASE = "/assets/viewer.html";

  // Parse /owner/repo/src/commit/{40hex}/{treepath}
  // Returns {repoPath, hash, treePath} or null.
  function parseCommitHref(href) {
    var m = href.match(/^\/([^/]+\/[^/]+)\/src\/commit\/([0-9a-f]{40})\/(.+)$/i);
    if (!m) return null;
    return { repoPath: m[1], hash: m[2], treePath: m[3] };
  }

  function makeViewerLink(info, label, cls) {
    var host   = window.location.host;
    var ifcUrl = "ifc://" + host + "/" + info.repoPath
               + "@" + info.hash
               + "?path=" + encodeURIComponent(info.treePath);
    var a = document.createElement("a");
    a.href       = VIEWER_BASE + "?url=" + encodeURIComponent(ifcUrl);
    a.target     = "_blank";
    a.rel        = "noopener noreferrer";
    a.className  = cls || "ui mini basic button";
    a.textContent = label;
    return a;
  }

  function init() {
    var host = window.location.host;

    // -----------------------------------------------------------------------
    // Case 1: single file view — permalink button in .file-header-right.
    // -----------------------------------------------------------------------
    var btnGroup = document.querySelector(".file-header-right .ui.buttons");
    if (btnGroup) {
      // Permalink href or current URL when already at a commit.
      var a = document.querySelector('a[href*="/src/commit/"]');
      var href = a ? a.getAttribute("href") : window.location.pathname;
      var info = parseCommitHref(href);
      if (info && info.treePath.toLowerCase().endsWith(".ifc")) {
        btnGroup.appendChild(makeViewerLink(info, "View in 3D"));
      }
      return;
    }

    // -----------------------------------------------------------------------
    // Case 3: PR diff page — inject a render_diff image below the header of
    // each .ifc file in the diff.  Requires Nginx to proxy /render_diff to
    // the ifcurl preview service (see forgejo/README.md).
    // -----------------------------------------------------------------------
    var prMatch = window.location.pathname.match(/^\/([^/]+\/[^/]+)\/pulls\/(\d+)\/files$/);
    if (prMatch) {
      var prRepoPath = prMatch[1];
      var prNum = prMatch[2];
      fetch("/api/v1/repos/" + prRepoPath + "/pulls/" + prNum)
        .then(function(r) { return r.ok ? r.json() : Promise.reject(r.status); })
        .then(function(pr) {
          var baseSha = pr.base && pr.base.sha;
          var headSha = pr.head && pr.head.sha;
          if (!baseSha || !headSha) return;
          var origin = window.location.origin;
          document.querySelectorAll('a[href*="/src/commit/"]').forEach(function(a) {
            var info = parseCommitHref(a.getAttribute("href"));
            if (!info || !info.treePath.toLowerCase().endsWith(".ifc")) return;
            if (info.hash !== headSha) return;
            var baseIfc = "ifc://" + host + "/" + prRepoPath + "@" + baseSha
                        + "?path=" + encodeURIComponent(info.treePath);
            var headIfc = "ifc://" + host + "/" + prRepoPath + "@" + headSha
                        + "?path=" + encodeURIComponent(info.treePath);
            var img = document.createElement("img");
            img.src = origin + "/render_diff"
                    + "?base=" + encodeURIComponent(baseIfc)
                    + "&head=" + encodeURIComponent(headIfc);
            img.style.cssText = "max-width:100%;display:block;margin:8px 0";
            img.alt = info.treePath;
            var fileBox = a.closest(".diff-file-box");
            var header = fileBox && fileBox.querySelector(".file-header");
            if (header) {
              header.insertAdjacentElement("afterend", img);
            } else {
              a.insertAdjacentElement("afterend", img);
            }
          });
        })
        .catch(function() {}); // silently skip on API error
      return;
    }

    // -----------------------------------------------------------------------
    // Case 4: individual commit page — inject a render_diff image (or plain
    // preview for added/deleted files) below the header of each .ifc file
    // in the diff.
    // -----------------------------------------------------------------------
    var commitMatch = window.location.pathname.match(/^\/([^/]+\/[^/]+)\/commit\/([0-9a-f]{40})$/i);
    if (commitMatch) {
      var repoPath = commitMatch[1];
      var headSha = commitMatch[2];
      var origin = window.location.origin;

      // Extract parent SHA from the "parent" commit link at the top of the page.
      var parentSha = null;
      var parentLink = document.querySelector("a.primary.sha.label[href*='/commit/']");
      if (parentLink) {
        var pm = parentLink.getAttribute("href").match(/\/commit\/([0-9a-f]{40})$/i);
        if (pm) parentSha = pm[1];
      }

      document.querySelectorAll(".diff-file-box").forEach(function(box) {
        var newFile = box.getAttribute("data-new-filename") || "";
        var oldFile = box.getAttribute("data-old-filename") || "";
        var newIsIfc = newFile.toLowerCase().endsWith(".ifc");
        var oldIsIfc = oldFile.toLowerCase().endsWith(".ifc");

        var ifcPath, imgSrc;
        if (newIsIfc && oldIsIfc && newFile === oldFile && parentSha) {
          // Modified: show colour-coded diff
          ifcPath = newFile;
          var baseIfc = "ifc://" + host + "/" + repoPath + "@" + parentSha + "?path=" + encodeURIComponent(ifcPath);
          var headIfc = "ifc://" + host + "/" + repoPath + "@" + headSha + "?path=" + encodeURIComponent(ifcPath);
          imgSrc = origin + "/render_diff?base=" + encodeURIComponent(baseIfc) + "&head=" + encodeURIComponent(headIfc);
        } else if (newIsIfc) {
          // Added (or renamed to .ifc): plain preview of new version
          ifcPath = newFile;
          imgSrc = origin + "/preview?url=" + encodeURIComponent("ifc://" + host + "/" + repoPath + "@" + headSha + "?path=" + encodeURIComponent(ifcPath));
        } else if (oldIsIfc && parentSha) {
          // Deleted (or renamed from .ifc): plain preview of old version
          ifcPath = oldFile;
          imgSrc = origin + "/preview?url=" + encodeURIComponent("ifc://" + host + "/" + repoPath + "@" + parentSha + "?path=" + encodeURIComponent(ifcPath));
        } else {
          return;
        }

        var img = document.createElement("img");
        img.src = imgSrc;
        img.style.cssText = "max-width:100%;display:block;margin:8px 0";
        img.alt = ifcPath;
        var header = box.querySelector(".diff-file-header");
        if (header) header.insertAdjacentElement("afterend", img);
      });
      return;
    }

    // -----------------------------------------------------------------------
    // Case 2: file history page — inject a "3D" link next to each commit's
    // browse-file link (/src/commit/{hash}/{treepath}).
    // -----------------------------------------------------------------------
    document.querySelectorAll('a[href*="/src/commit/"]').forEach(function(a) {
      var info = parseCommitHref(a.getAttribute("href"));
      if (!info || !info.treePath.toLowerCase().endsWith(".ifc")) return;
      var btn = makeViewerLink(info, "3D");
      btn.style.marginLeft = "4px";
      a.insertAdjacentElement("afterend", btn);
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
</script>
