'use strict';

const tryGetDocument = require('./try-get-document-c0ebd39a.js');

/**
 * VegaNonceManager is responsible for managing the CSP nonce value.
 */
class VegaNonceManager {
  /**
   * Creates a new instance of the nonce manager.
   *
   * If a `nonce` is provided, it will be used as the internal nonce value.
   * If not provided, and if the environment supports `tryGetDocument`, attempts to retrieve
   * the nonce from a meta tag with the name "csp-nonce" in the document.
   *
   * @param {string | undefined} nonce - An optional string representing the CSP nonce to use.
   */
  constructor(nonce) {
    var _a;
    if (nonce) {
      this._nonce = nonce;
    }
    else if (typeof tryGetDocument.tryGetDocument === 'function') {
      const dom = tryGetDocument.tryGetDocument();
      if (dom) {
        const metaNonce = (_a = dom.querySelector('meta[name="csp-nonce"]')) === null || _a === void 0 ? void 0 : _a.content;
        if (metaNonce) {
          this._nonce = metaNonce;
        }
      }
    }
  }
  /**
   * Sets the Content Security Policy (CSP) nonce value.
   *
   * @param {string | undefined} nonce - The nonce string to be set, or `undefined` to clear the nonce.
   */
  set nonce(nonce) {
    this._nonce = nonce;
  }
  /**
   * Gets the current Content Security Policy (CSP) nonce value.
   *
   * @returns {string | undefined} The current nonce string, or `undefined` if not set.
   */
  get nonce() {
    return this._nonce;
  }
  /**
   * Monkey-patches document.head.insertBefore to automatically add the CSP nonce
   * to dynamically injected <style> elements with the 'data-styles' attribute.
   *
   * This ensures that styles injected at runtime comply with the Content Security Policy.
   */
  patchHeadInsertBeforeWithNonceToStencil() {
    const doc = tryGetDocument.tryGetDocument();
    if (!doc)
      return;
    const head = doc.head;
    const originalHeadInsertBefore = head.insertBefore;
    /**
     * Overrides the head.insertBefore method to inject a CSP nonce into any STYLE element being inserted.
     *
     * @template T - The type of Node being inserted.
     * @param {T} newElement - The new node to insert.
     * @param {Node | null} referenceElement - The node before which newElement is inserted, or null to insert at the end.
     * @returns {T} The inserted node.
     */
    head.insertBefore = function (newElement, referenceElement) {
      // If no nonce is set, use the original insertBefore
      if (!vegaNonceManager.nonce)
        return originalHeadInsertBefore.call(this, newElement, referenceElement);
      // Check if the new element is a <style> tag injected by Stencil (with data-styles and vega- marker or .hydrated)
      if (newElement.nodeType === Node.ELEMENT_NODE &&
        newElement instanceof HTMLStyleElement &&
        newElement.hasAttribute('data-styles') &&
        (newElement.innerHTML.includes('vega-') || newElement.innerHTML.includes('.hydrated')) &&
        !newElement.hasAttribute('nonce')) {
        newElement.setAttribute('nonce', vegaNonceManager.nonce);
      }
      return originalHeadInsertBefore.call(this, newElement, referenceElement);
    };
  }
}
/**
 * Singleton instance of the {@link VegaNonceManager} used to manage CSP nonce across the application.
 */
const vegaNonceManager = new VegaNonceManager();
/**
 * Sets the nonce value used by the Vega nonce manager.
 *
 * This function updates the `nonce` property of the global `vegaNonceManager`
 * object with the provided nonce string. The nonce is typically used for
 * Content Security Policy (CSP) compliance when dynamically injecting scripts or styles.
 *
 * @param {string | undefined} nonce - The nonce string to be set for CSP compliance.
 */
function setVegaNonce(nonce) {
  vegaNonceManager.nonce = nonce;
}

exports.VegaNonceManager = VegaNonceManager;
exports.setVegaNonce = setVegaNonce;
exports.vegaNonceManager = vegaNonceManager;
