(function() {
  /** @type {import("../htmx").HtmxInternalApi} */
  var api

  var attrPrefix = 'hx-target-'

  // IE11 doesn't support string.startsWith
  function startsWith(str, prefix) {
    return str.substring(0, prefix.length) === prefix
  }

  /**
     * @param {HTMLElement} elt
     * @param {number} respCode
     * @returns {HTMLElement | null}
     */
  function getRespCodeTarget(elt, respCodeNumber) {
    if (!elt || !respCodeNumber) return null

    var respCode = respCodeNumber.toString()

    // '*' is the original syntax, as the obvious character for a wildcard.
    // The 'x' alternative was added for maximum compatibility with HTML
    // templating engines, due to ambiguity around which characters are
    // supported in HTML attributes.
    //
    // Start with the most specific possible attribute and generalize from
    // there.
    var attrPossibilities = [
      respCode,

      respCode.substring(0, 2) + '*',
      respCode.substring(0, 2) + 'x',

      respCode.substring(0, 1) + '*',
      respCode.substring(0, 1) + 'x',
      respCode.substring(0, 1) + '**',
      respCode.substring(0, 1) + 'xx',

      '*',
      'x',
      '***',
      'xxx'
    ]
    if (startsWith(respCode, '4') || startsWith(respCode, '5')) {
      attrPossibilities.push('error')
    }

    for (var i = 0; i < attrPossibilities.length; i++) {
      var attr = attrPrefix + attrPossibilities[i]
      var attrValue = api.getClosestAttributeValue(elt, attr)
      if (attrValue) {
        if (attrValue === 'this') {
          return api.findThisElement(elt, attr)
        } else {
          return api.querySelectorExt(elt, attrValue)
        }
      }
    }

    return null
  }

  /** @param {Event} evt */
  function handleErrorFlag(evt) {
    if (evt.detail.isError) {
      if (htmx.config.responseTargetUnsetsError) {
        evt.detail.isError = false
      }
    } else if (htmx.config.responseTargetSetsError) {
      evt.detail.isError = true
    }
  }

  htmx.defineExtension('response-targets', {

    /** @param {import("../htmx").HtmxInternalApi} apiRef */
    init: function(apiRef) {
      api = apiRef

      if (htmx.config.responseTargetUnsetsError === undefined) {
        htmx.config.responseTargetUnsetsError = true
      }
      if (htmx.config.responseTargetSetsError === undefined) {
        htmx.config.responseTargetSetsError = false
      }
      if (htmx.config.responseTargetPrefersExisting === undefined) {
        htmx.config.responseTargetPrefersExisting = false
      }
      if (htmx.config.responseTargetPrefersRetargetHeader === undefined) {
        htmx.config.responseTargetPrefersRetargetHeader = true
      }
    },

    /**
         * @param {string} name
         * @param {Event} evt
         */
    onEvent: function(name, evt) {
      if (name === 'htmx:beforeSwap' &&
                evt.detail.xhr &&
                evt.detail.xhr.status !== 200) {
        if (evt.detail.target) {
          if (htmx.config.responseTargetPrefersExisting) {
            evt.detail.shouldSwap = true
            handleErrorFlag(evt)
            return true
          }
          if (htmx.config.responseTargetPrefersRetargetHeader &&
                        evt.detail.xhr.getAllResponseHeaders().match(/HX-Retarget:/i)) {
            evt.detail.shouldSwap = true
            handleErrorFlag(evt)
            return true
          }
        }
        if (!evt.detail.requestConfig) {
          return true
        }
        var target = getRespCodeTarget(evt.detail.requestConfig.elt, evt.detail.xhr.status)
        if (target) {
          handleErrorFlag(evt)
          evt.detail.shouldSwap = true
          evt.detail.target = target
        }
        return true
      }
    }
  })
})()
