import retrace from “retrace”

export default class ErrorLogger {

constructor() {
  this.errors = []
}

loadSourceMaps() {
  return new Promise(resolve => {
    var scripts = document.querySelectorAll("script")
    var promises = []

    for(var script of scripts) {
      var src = script.getAttribute("src")
      var type = script.getAttribute("type")

      if (src && src.includes("/packs/") && (type == "text/javascript" || !type)) {
        var promise = this.loadSourceMapForScript(script)
        promises.push(promise)
      }
    }

    Promise.all(promises).then(() => { resolve() })
  })
}

loadSourceMapForScript(script) {
  var src = script.getAttribute("src")
  var url = this.loadUrl(src)
  var originalUrl = `${url.origin}${url.pathname}`
  var mapUrl = `${url.origin}${url.pathname}.map`

  return new Promise(resolve => {
    var xhr = new XMLHttpRequest()
    xhr.open("GET", mapUrl, true)
    xhr.onload = () => {
      retrace.register(originalUrl, xhr.responseText)
      resolve()
    }
    xhr.send()
  })
}

loadUrl(url) {
  var parser = document.createElement("a")
  parser.href = url

  return parser
}

enable() {
  this.connectOnError()
  this.connectUnhandledRejection()
}

getErrors() {
  return this.errors
}

connectOnError() {
  window.addEventListener("error", (event) => {
    if (!this.isHandlingError) {
      try {
        this.isHandlingError = true
        this.errors.push({
          errorClass: event.error ? event.error.name : "No error class",
          file: event.filename,
          message: event.message || "Unknown error",
          url: window.location.href,
          line: event.lineno,
          error: event.error
        })
      } finally {
        this.isHandlingError = false
      }
    }
  })
}

connectUnhandledRejection() {
  window.addEventListener("unhandledrejection", (event, test) => {
    if (!this.isHandlingError) {
      this.isHandlingError = true

      try {
        if (event.reason.stack) {
          retrace.map(event.reason.stack).then(mappedStackTrace => {
            this.errors.push({
              errorClass: "UnhandledRejection",
              file: null,
              message: event.reason.message || "Unhandled promise rejection",
              url: window.location.href,
              line: null,
              backtrace: mappedStackTrace.split("\n")
            })
          })
        } else {
          this.errors.push({
            errorClass: "UnhandledRejection",
            file: null,
            message: event.reason.message || "Unhandled promise rejection",
            url: window.location.href,
            line: null,
            backtrace: null
          })
        }
      } finally {
        this.isHandlingError = false
      }
    }
  })
}

testPromiseError() {
  return new Promise(resolve => {
    throw new Error("testPromiseError")
  })
}

}