import { formSubmitSelector, buttonClickSelector, inputChangeSelector } from "../utils/constants"
import { ajax, isCrossDomain } from "../utils/ajax"
import { matches, getData, setData } from "../utils/dom"
import { fire, stopEverything } from "../utils/event"
import { serializeElement } from "../utils/form"
import { isContentEditable } from "../utils/dom"

// Checks "data-remote" if true to handle the request through a XHR request.
const isRemote = function(element) {
  const value = element.getAttribute("data-remote")
  return (value != null) && (value !== "false")
}

// Submits "remote" forms and links with ajax
const handleRemoteWithRails = (rails) => function(e) {
  let data, method, url
  const element = this

  if (!isRemote(element)) { return true }
  if (!fire(element, "ajax:before")) {
    fire(element, "ajax:stopped")
    return false
  }

  if (isContentEditable(element)) {
    fire(element, "ajax:stopped")
    return false
  }

  const withCredentials = element.getAttribute("data-with-credentials")
  const dataType = element.getAttribute("data-type") || "script"

  if (matches(element, formSubmitSelector)) {
    // memoized value from clicked submit button
    const button = getData(element, "ujs:submit-button")
    method = getData(element, "ujs:submit-button-formmethod") || element.getAttribute("method") || "get"
    url = getData(element, "ujs:submit-button-formaction") || element.getAttribute("action") || location.href

    // strip query string if it's a GET request
    if (method.toUpperCase() === "GET") { url = url.replace(/\?.*$/, "") }

    if (element.enctype === "multipart/form-data") {
      data = new FormData(element)
      if (button != null) { data.append(button.name, button.value) }
    } else {
      data = serializeElement(element, button)
    }

    setData(element, "ujs:submit-button", null)
    setData(element, "ujs:submit-button-formmethod", null)
    setData(element, "ujs:submit-button-formaction", null)
  } else if (matches(element, buttonClickSelector) || matches(element, inputChangeSelector)) {
    method = element.getAttribute("data-method")
    url = element.getAttribute("data-url")
    data = serializeElement(element, element.getAttribute("data-params"))
  } else {
    method = element.getAttribute("data-method")
    url = rails.href(element)
    data = element.getAttribute("data-params")
  }

  ajax({
    type: method || "GET",
    url,
    data,
    dataType,
    // stopping the "ajax:beforeSend" event will cancel the ajax request
    beforeSend(xhr, options) {
      if (fire(element, "ajax:beforeSend", [xhr, options])) {
        return fire(element, "ajax:send", [xhr])
      } else {
        fire(element, "ajax:stopped")
        return false
      }
    },
    success(...args) { return fire(element, "ajax:success", args) },
    error(...args) { return fire(element, "ajax:error", args) },
    complete(...args) { return fire(element, "ajax:complete", args) },
    crossDomain: isCrossDomain(url),
    withCredentials: (withCredentials != null) && (withCredentials !== "false")
  })
  stopEverything(e)
}

const formSubmitButtonClick = function(e) {
  const button = this
  const {
    form
  } = button
  if (!form) { return }
  // Register the pressed submit button
  if (button.name) { setData(form, "ujs:submit-button", {name: button.name, value: button.value}) }
  // Save attributes from button
  setData(form, "ujs:formnovalidate-button", button.formNoValidate)
  setData(form, "ujs:submit-button-formaction", button.getAttribute("formaction"))
  return setData(form, "ujs:submit-button-formmethod", button.getAttribute("formmethod"))
}

const preventInsignificantClick = function(e) {
  const link = this
  const method = (link.getAttribute("data-method") || "GET").toUpperCase()
  const data = link.getAttribute("data-params")
  const metaClick = e.metaKey || e.ctrlKey
  const insignificantMetaClick = metaClick && (method === "GET") && !data
  const nonPrimaryMouseClick = (e.button != null) && (e.button !== 0)
  if (nonPrimaryMouseClick || insignificantMetaClick) { e.stopImmediatePropagation() }
}

export { handleRemoteWithRails, formSubmitButtonClick, preventInsignificantClick }
