import React, { useEffect, useState } from "react";
import { Sha256 } from "@aws-crypto/sha256-browser";
import bs58 from "bs58";
import { ConnectionFailureTemplate, DefaultTemplate, NoTemplate, TamperedSvgTemplate } from "../../DefaultTemplate";
import handlebars from "handlebars";
import { jsx as ___EmotionJSX } from "@emotion/react";
const fetchSvg = async (svgInDoc, abortController) => {
  const response = await fetch(svgInDoc, {
    signal: abortController.signal
  });
  if (!response.ok) {
    throw new Error("Failed to fetch remote SVG");
  }
  const blob = await response.blob();
  const res = await blob.arrayBuffer();
  return res;
};
const renderSvg = (template, document) => {
  if (template.length === 0) return "";
  const compiledTemplate = handlebars.compile(template);
  return document.credentialSubject ? compiledTemplate(document.credentialSubject) : compiledTemplate(document);
};

// As specified in - https://w3c-ccg.github.io/vc-render-method/#svgrenderingtemplate2023
export const SVG_RENDERER_TYPE = "SvgRenderingTemplate2023";

/**
 * Component that accepts a v4 document to fetch and display the first available template SVG
 */
const SvgRenderer = /*#__PURE__*/React.forwardRef((_ref, ref) => {
  var _document$renderMetho, _renderMethod$id;
  let {
    document,
    style,
    className,
    onResult,
    loadingComponent
  } = _ref;
  const [toDisplay, setToDisplay] = useState({
    status: "LOADING"
  });
  const renderMethod = (_document$renderMetho = document.renderMethod) === null || _document$renderMetho === void 0 ? void 0 : _document$renderMetho.find(method => method.type === SVG_RENDERER_TYPE);
  const svgInDoc = (_renderMethod$id = renderMethod === null || renderMethod === void 0 ? void 0 : renderMethod.id) !== null && _renderMethod$id !== void 0 ? _renderMethod$id : "";
  useEffect(() => {
    setToDisplay({
      status: "LOADING"
    });

    /** for what ever reason, the SVG template is missing or invalid */
    const handleInvalidSvgTemplate = result => {
      setToDisplay(result);
      onResult === null || onResult === void 0 || onResult(result);
    };

    /** we have everything we need to generate the svg data uri, but we do not know if
     * it is malformed/blocked by CORS or not until it is loaded by the image element,
     * hence we do not call onResult here, instead we call it in the img onLoad and
     * onError handlers
     */
    const handleValidSvgTemplate = rawSvgTemplate => {
      setToDisplay({
        status: "PENDING_OK",
        svgDataUri: "data:image/svg+xml,".concat(encodeURIComponent(renderSvg(rawSvgTemplate, document)))
      });
    };
    if (renderMethod === undefined) {
      handleInvalidSvgTemplate({
        status: "DEFAULT"
      });
      return;
    }
    const abortController = new AbortController();
    const urlPattern = /^https?:\/\/.*\.svg$/;
    const isSvgUrl = urlPattern.test(svgInDoc);
    if (!isSvgUrl) {
      // Case 1: SVG is embedded in the doc, can directly display
      handleValidSvgTemplate(svgInDoc);
    } else {
      // Case 2: SVG is a url, fetch and check digestMultibase if provided
      fetchSvg(svgInDoc, abortController).then(buffer => {
        const digestMultibaseInDoc = renderMethod === null || renderMethod === void 0 ? void 0 : renderMethod.digestMultibase;
        const svgUint8Array = new Uint8Array(buffer !== null && buffer !== void 0 ? buffer : []);
        const decoder = new TextDecoder();
        const rawSvgTemplate = decoder.decode(svgUint8Array);
        if (!digestMultibaseInDoc) {
          handleValidSvgTemplate(rawSvgTemplate);
        } else {
          const hash = new Sha256();
          hash.update(svgUint8Array);
          hash.digest().then(shaDigest => {
            const recomputedDigestMultibase = "z" + bs58.encode(shaDigest); // manually prefix with 'z' as per https://w3c-ccg.github.io/multibase/#mh-registry
            if (recomputedDigestMultibase === digestMultibaseInDoc) {
              handleValidSvgTemplate(rawSvgTemplate);
            } else {
              handleInvalidSvgTemplate({
                status: "DIGEST_ERROR"
              });
            }
          });
        }
      }).catch(error => {
        if (error.name !== "AbortError") {
          handleInvalidSvgTemplate({
            status: "FETCH_SVG_ERROR",
            error
          });
        }
      });
    }
    return () => {
      abortController.abort();
    };
  }, [document, onResult, svgInDoc, renderMethod]);
  const handleImgResolved = result => () => {
    setToDisplay(result);
    onResult === null || onResult === void 0 || onResult(result);
  };
  switch (toDisplay.status) {
    case "LOADING":
      return loadingComponent ? ___EmotionJSX(React.Fragment, null, loadingComponent) : null;
    case "SVG_LOAD_ERROR":
      return ___EmotionJSX(DefaultTemplate, {
        title: "The resolved SVG could not be loaded",
        description: ___EmotionJSX(React.Fragment, null, "The resolved SVG is either blocked or malformed. Please contact the issuer."),
        document: document
      });
    case "FETCH_SVG_ERROR":
      return ___EmotionJSX(ConnectionFailureTemplate, {
        document: document,
        source: svgInDoc
      });
    case "DIGEST_ERROR":
      return ___EmotionJSX(TamperedSvgTemplate, {
        document: document
      });
    case "PENDING_OK":
    case "OK":
      {
        return ___EmotionJSX("img", {
          className: className,
          style: toDisplay.status === "PENDING_OK" ? {
            display: "none"
          } : style,
          title: "Svg Renderer Image",
          src: toDisplay.svgDataUri,
          ref: ref,
          alt: "Svg image of the verified document",
          onLoad: handleImgResolved({
            status: "OK",
            svgDataUri: toDisplay.svgDataUri
          }),
          onError: handleImgResolved({
            status: "SVG_LOAD_ERROR",
            svgDataUri: toDisplay.svgDataUri
          })
        });
      }
    default:
      return ___EmotionJSX(NoTemplate, {
        document: document,
        handleObfuscation: () => null
      });
  }
});
SvgRenderer.displayName = "SvgRendererComponent";
export { SvgRenderer };
//# sourceMappingURL=SvgRenderer.js.map