<!-- Excalidraw -->
<link rel="stylesheet" href="https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/dev/index.css">
<!-- <link rel="stylesheet" href="{{ 'css/excalidraw.css' | url }}">" -->
<script type="importmap">
      {
        "imports": {
          "react": "https://esm.sh/react@19.0.0",
          "react/jsx-runtime": "https://esm.sh/react@19.0.0/jsx-runtime",
          "react-dom": "https://esm.sh/react-dom@19.0.0"
        }
      }
</script>
<script type="module">
  // window.EXCALIDRAW_ASSET_PATH = "/mkdocs-shadcn/";
  // for fonts
  // window.EXCALIDRAW_ASSET_PATH = "https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/prod/";
  // See https://www.npmjs.com/package/@excalidraw/excalidraw documentation.
  import {
    Excalidraw,
    exportToSvg,
    convertToExcalidrawElements,
  } from "https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/dev/index.js?external=react,react-dom";
  import React from "https://esm.sh/react@19.0.0";
  import { createRoot } from "https://esm.sh/react-dom@19.0.0/client";
  // import { React, createRoot, Excalidraw, exportToSvg, convertToExcalidrawElements } from "{{ 'js/excalidraw/index.js' | url }}";

  // This function append two elements at the top left and bottom right of the canvas
  // to make sure the canvas is always the same size as the excalidraw canvas
  // This is needed because excalidraw crops the canvas around the elements
  function shiftBoundElements(elements, appState) {
    const extraPoints = convertToExcalidrawElements([
      {
        type: "freedraw",
        x: 0,
        y: 0,
        width: 0.0,
        height: 0.0,
        points: [
          [0, 0],
          [0, 0],
        ],
        opacity: 0,
        pressures: [],
      },
      {
        type: "freedraw",
        x: appState.width,
        y: appState.height,
        width: 0.0,
        height: 0.0,
        points: [
          [0, 0],
          [0, 0],
        ],
        opacity: 0,
        pressures: [],
      },
    ]);
    return [
      ...elements.map((e) => {
        return { ...e, x: e.x + appState.scrollX, y: e.y + appState.scrollY };
      }),
      ...extraPoints,
    ];
  }

  function debounce(func, timeout = 1000) {
    let timer;
    return (...args) => {
      clearTimeout(timer);
      timer = setTimeout(() => {
        func.apply(this, args);
      }, timeout);
    };
  }


  async function toSVG(elements, appState, files) {
    const svg = await exportToSvg({
      elements: shiftBoundElements(elements, appState),
      appState: { ...appState, exportBackground: false },
      files,
      exportPadding: 0,
      metadata: "mkdocs-shadcn",
    });

    svg.innerHTML =
      `<g transform="scale(${appState.zoom.value})">` +
      svg.innerHTML.replaceAll("#1e1e1e", "currentColor") +
      "</g>";
    return svg;
  }

  function ResizableDiv({ height, onResize, children }) {
    const isResizing = React.useRef(false);
    const startY = React.useRef(0);
    const startHeight = React.useRef(0);

    const onMouseDown = (e) => {
      isResizing.current = true;
      startY.current = e.clientY;
      startHeight.current = height;
      document.addEventListener("mousemove", onMouseMove);
      document.addEventListener("mouseup", onMouseUp);
    };

    const onMouseMove = (e) => {
      if (!isResizing.current) return;
      const delta = e.clientY - startY.current;
      const newHeight = Math.max(50, startHeight.current + delta);
      onResize(newHeight);
    };

    const onMouseUp = () => {
      isResizing.current = false;
      document.removeEventListener("mousemove", onMouseMove);
      document.removeEventListener("mouseup", onMouseUp);
    };

    return React.createElement(
      "div",
      {
        className: "relative",
        style: { height: `${height}px` },
      },
      React.createElement(
        "div",
        { className: "h-full" },
        children,
      ),
      React.createElement(
        "div",
        {
          onMouseDown,
          className:
            "absolute z-40 -bottom-3 left-0 right-0 h-3 cursor-ns-resize group flex flex-row items-center",
        },
        React.createElement("div", {
          className:
            "w-full h-[1px] group-hover:bg-primary bg-border transition-colors",
        }),
      ),
    );
  }


  function fetchScene(file) {
    return fetch(`/excalidraw/scene?file=${file}`, { method: "GET" })
      .then((response) => response.json())
  }


  function saveScene(file, elements, appState, files) {
    return fetch(`/excalidraw/scene?file=${file}`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        elements,
        appState,
        files,
      })
    })
  };



  function fetchSVG(file) {
    return fetch(`/excalidraw/svg?file=${file}`, { method: "GET" })
      .then((response) => response.text())
      .then((txt) => {
        const parser = new DOMParser();
        const doc = parser.parseFromString(txt, 'image/svg+xml');
        const svgElement = doc.querySelector('svg');
        return svgElement;
      });
  };

  function saveSVG(file, ref) {
    return fetch(`/excalidraw/svg?file=${file}`, {
      method: "POST",
      headers: {
        "Content-Type": "image/svg+xml",
      },
      body: ref.current?.outerHTML
    })
  }

  function updateSVG(element, ref) {
    // update the svg element (react ref) with the new content
    if (ref.current) {
      for (const attr of ["version", "width", "height", "viewBox", "xmlns"]) {
        ref.current.setAttribute(
          attr,
          element.attributes.getNamedItem(attr).value,
        );
      }
      ref.current.setAttribute("width", "100%");
      ref.current.innerHTML = element.innerHTML;
    }
  };

  function App({ file, viewModeEnabled = false }) {
    // API to call excalidraw functions (mainly to retrive the inner scene)
    const [excalidrawAPI, setExcalidrawAPI] = React.useState(null);
    // State to toggle edit mode (it shows the excalidraw editor alongside the svg)
    const [edit, setEdit] = React.useState(false);
    const svgRef = React.useRef(null); // ref to the svg element
    const [right, setRight] = React.useState(0); // offset to position the excalidraw editor
    const containerRef = React.useRef(null); // outer container to compute the right offset
    const [height, setHeight] = React.useState(400);


    // download data
    React.useEffect(() => {
      if (edit && excalidrawAPI) {
        fetchScene(file).then((data) => {
          setHeight(data.appState.height);
          excalidrawAPI.updateScene({ ...data });
          excalidrawAPI.refresh();
        });
      } else {
        fetchSVG(file).then((svg) => {
          if (svg) {
            setHeight(svg.attributes.getNamedItem("height").value);
            if (svgRef.current) {
              updateSVG(svg, svgRef);
            }
          }
        });
      }

    }, [file, edit, excalidrawAPI]);
    // Position the excalidraw editor properly if we have not enough place
    // on the right side
    React.useEffect(() => {
      if (edit && containerRef.current) {
        const { right, width } = containerRef.current.getBoundingClientRect();
        setRight(Math.min(Math.max(window.innerWidth - right - 15, width / 2), width));
      }
    }, [edit, containerRef.current]);


    const debounceSaveScene = debounce(saveScene, 1000);
    const debounceSaveSVG = debounce(saveSVG, 1000);

    // Update the svg and save the scene when the excalidraw scene changes
    const onChange = React.useCallback(
      async (elements, appState, files) => {
        // update the scg draw
        const svg = await toSVG(elements, appState, files);
        updateSVG(svg, svgRef);
        await debounceSaveSVG(file, svgRef);
        await debounceSaveScene(file, elements, appState, files);
      },
      [file],
    );

    const onEditChange = () => {
      setEdit((prev) => !prev);
    }

    return React.createElement(
      React.Fragment,
      null,
      React.createElement(
        "div",
        {
          ref: containerRef,
          className: "h-fit w-full relative group/container",
        },
        React.createElement("svg", { ref: svgRef }),
        React.createElement(
          "div",
          {
            className:
              "absolute z-20 opacity-0 top-0 left-0 flex flex-row gap-2 items-center group-hover/container:opacity-100 transition-color duration-500",
          },
          React.createElement(
            "span",
            { className: "text-sm text-muted-foreground leading-none" },
            "Edit",
          ),
          React.createElement("input", {
            type: "checkbox",
            checked: edit,
            onChange: onEditChange,
            className:
              "h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 accent-primary",
          }),
        ),
        React.createElement(
          "div",
          { className: "absolute h-full top-0 w-full", style: { right: -right } },
          edit ?
            React.createElement(
              ResizableDiv,
              { height: height, onResize: setHeight },
              React.createElement(
                "div",
                {
                  "data-scene": file,
                  className:
                    "h-full w-full rounded overflow-hidden border relative shadow",
                },
                React.createElement(Excalidraw, {
                  excalidrawAPI: (api) => setExcalidrawAPI(api),
                  onChange,
                  viewModeEnabled: false,
                  zenModeEnabled: false,
                  isCollaborating: false,
                }),
              ),
            )
            : null,
        ),
      ),
    );
  }

  window.excalidraw = (id, viewModeEnabled = false) => {
    const excalidrawWrapper = document.getElementById(id);
    if (!excalidrawWrapper) {
      console.error(`No container with id=${id} found`);
      return;
    }
    const file = excalidrawWrapper.attributes.getNamedItem("data-scene").value;
    const root = createRoot(excalidrawWrapper);
    root.render(React.createElement(App, { file: file, viewModeEnabled }));
  };
</script>