import "./browser-patch.mjs";
import Parser from 'web-tree-sitter';
import { ApiDOMError } from '@swagger-api/apidom-error';

// @ts-ignore
import treeSitterJson from '../../wasm/tree-sitter-json.wasm';
let parser = null;
let parserInitLock = null;
const activeTrees = new Set();
const MAX_ACTIVE_TREES = 10;

/**
 * Lexical Analysis of source string using WebTreeSitter.
 * This is WebAssembly version of TreeSitters Lexical Analysis.
 * @public
 */
const analyze = async source => {
  if (parser === null && parserInitLock === null) {
    // acquire lock
    parserInitLock = Parser.init().then(() => Parser.Language.load(treeSitterJson)).then(jsonLanguage => {
      const parserInstance = new Parser();
      parserInstance.setLanguage(jsonLanguage);
      return parserInstance;
    }).finally(() => {
      // release lock
      parserInitLock = null;
    });
    parser = await parserInitLock;
  } else if (parser === null && parserInitLock !== null) {
    // await for lock to be released if there is one
    parser = await parserInitLock;
  } else if (parser === null) {
    throw new ApiDOMError('Error while initializing web-tree-sitter and loading tree-sitter-json grammar.');
  }

  // prevent WASM OOM during concurrency spikes by evicting oldest trees
  // when the pool exceeds threshold; tree.delete() is idempotent so
  // callers that still hold a reference can safely call delete() again
  if (activeTrees.size >= MAX_ACTIVE_TREES) {
    const treesToEvict = [...activeTrees];
    activeTrees.clear();
    for (const oldTree of treesToEvict) {
      oldTree.delete();
    }
  }
  const tree = parser.parse(source);
  activeTrees.add(tree);

  // remove from tracking when caller deletes
  const originalDelete = tree.delete;
  tree.delete = function deleteAndUntrack() {
    activeTrees.delete(this);
    originalDelete.call(this);
  };
  parser.reset();
  return tree;
};
export default analyze;