import cachedUris from './contexts.js';
import jsonFetch from '../utils/json-fetch.js';
import './contexts/vc-examples-v1.js';
import './contexts/security_context.js';
import './contexts/status-list-21.js';
import './contexts/private-status-list-21.js';

function parseEmbeddedDataURI(embedded) {
  // Strip new lines
  const dataUri = embedded.replace(/\r?\n/g, '');

  // split the URI up into the "metadata" and the "data" portions
  const firstComma = dataUri.indexOf(',');
  if (firstComma === -1) {
    throw new Error('Malformed data URI');
  }

  // Remove the scheme and parse metadata
  const meta = dataUri.substring(5, firstComma).split(';'); // 'data:'.length = 5
  if (meta[0] !== 'application/json') {
    throw new Error(`Expected media type application/json but was ${meta[0]}`);
  }

  const isBase64 = meta.indexOf('base64') !== -1;
  if (isBase64) {
    throw new Error('Base64 embedded JSON is not yet supported');
  }

  // Extract data string
  const dataStr = decodeURIComponent(dataUri.substring(firstComma + 1));
  return JSON.parse(dataStr);
}

/**
 * @typedef {Object} DocumentLoaderResolver
 * @property {function(string): boolean} [supports]
 * @property {function(string): Promise<*>} [resolve]
 */

/**
 * Takes a resolver and returns a function that returns a document or throws an error when the document
 * cannot be found.
 * @param {DocumentLoaderResolver|null} [resolver] - Optional resolver for DID / status list / blob URLs when not served from the built-in context cache.
 * @returns {loadDocument} - the returned function
 */
function documentLoader(resolver = null) {
  /**
   * Resolve a URI. If the URI is a DID, then the resolver is used to resolve it.
   * Else, the hardcoded contexts are used to resolve the URI and if that fails
   * it will be fetched using an HTTP client
   * @param {string} uri
   * @returns {Promise<{documentUrl: string, contextUrl: string, document: *}>}
   */
  async function loadDocument(uri) {
    let document;
    const uriString = uri.toString();

    if (uriString.startsWith('data:')) {
      document = parseEmbeddedDataURI(uriString);
    } else if (resolver?.supports(uriString)) {
      // Try to resolve a DID and throw if cannot resolve
      document = await resolver.resolve(uriString);
    } else {
      // Strip ending slash from uri to determine cache key
      const cacheKey = uriString.endsWith('/')
        ? uriString.substring(0, uriString.length - 1)
        : uriString;

      // Check its not in data cache
      const cachedData = cachedUris.get(cacheKey);
      if (cachedData) {
        document = cachedData;
      } else {
        const doc = await jsonFetch(uriString);
        cachedUris.set(cacheKey, doc);
        document = doc;
      }
    }

    return {
      contextUrl: null,
      documentUrl: uri,
      document,
    };
  }

  return loadDocument;
}

export { documentLoader as default };
//# sourceMappingURL=document-loader.js.map
