// FIXME: es-module-shim won’t shim the dynamic import without this explicit import import “@hotwired/stimulus”

const controllerAttribute = “data-controller”

// Eager load all controllers registered beneath the ‘under` path in the import map to the passed application instance. export function eagerLoadControllersFrom(under, application) {

const paths = Object.keys(parseImportmapJson()).filter(path => path.match(new RegExp(`^${under}/.*_controller$`)))
paths.forEach(path => registerControllerFromPath(path, under, application))

}

function parseImportmapJson() {

return JSON.parse(document.querySelector("script[type=importmap]").text).imports

}

function registerControllerFromPath(path, under, application) {

const name = path
  .replace(new RegExp(`^${under}/`), "")
  .replace("_controller", "")
  .replace(/\//g, "--")
  .replace(/_/g, "-")

if (canRegisterController(name, application)) {
  import(path)
    .then(module => registerController(name, module, application))
    .catch(error => console.error(`Failed to register controller: ${name} (${path})`, error))
}

}

// Lazy load controllers registered beneath the ‘under` path in the import map to the passed application instance. export function lazyLoadControllersFrom(under, application, element = document) {

lazyLoadExistingControllers(under, application, element)
lazyLoadNewControllers(under, application, element)

}

function lazyLoadExistingControllers(under, application, element) {

queryControllerNamesWithin(element).forEach(controllerName => loadController(controllerName, under, application))

}

function lazyLoadNewControllers(under, application, element) {

new MutationObserver((mutationsList) => {
  for (const { attributeName, target, type } of mutationsList) {
    switch (type) {
      case "attributes": {
        if (attributeName == controllerAttribute && target.getAttribute(controllerAttribute)) {
          extractControllerNamesFrom(target).forEach(controllerName => loadController(controllerName, under, application))
        }
      }

      case "childList": {
        lazyLoadExistingControllers(under, application, target)
      }
    }
  }
}).observe(element, { attributeFilter: [controllerAttribute], subtree: true, childList: true })

}

function queryControllerNamesWithin(element) {

return Array.from(element.querySelectorAll(`[${controllerAttribute}]`)).map(extractControllerNamesFrom).flat()

}

function extractControllerNamesFrom(element) {

return element.getAttribute(controllerAttribute).split(/\s+/).filter(content => content.length)

}

function loadController(name, under, application) {

if (canRegisterController(name, application)) {
  import(controllerFilename(name, under))
    .then(module => registerController(name, module, application))
    .catch(error => console.error(`Failed to autoload controller: ${name}`, error))
}

}

function controllerFilename(name, under) {

return `${under}/${name.replace(/--/g, "/").replace(/-/g, "_")}_controller`

}

function registerController(name, module, application) {

if (canRegisterController(name, application)) {
  application.register(name, module.default)
}

}

function canRegisterController(name, application){

return !application.router.modulesByIdentifier.has(name)

}