const requestCache = new Map()
const cacheTtl = 10 * 1000

function isPreloadable (linkElement) {
  const href = linkElement.getAttribute('href')

  if (!href || href === '#' || linkElement.dataset.turbo === 'false' || linkElement.dataset.prefetch === 'false') {
    return
  }

  if (linkElement.origin !== document.location.origin) {
    return
  }

  if (!['http:', 'https:'].includes(linkElement.protocol)) {
    return
  }

  if (linkElement.pathname + linkElement.search === document.location.pathname + document.location.search) {
    return
  }

  if (linkElement.dataset.turboMethod && linkElement.dataset.turboMethod !== 'get') {
    return
  }

  return true
}

function mouseoverListener (event) {
  let linkElement

  if (event.target.tagName === 'A') {
    linkElement = event.target
  } else {
    linkElement = event.target.closest('a')
  }

  if (!linkElement) {
    return
  }

  if (!isPreloadable(linkElement)) {
    return
  }

  const url = linkElement.getAttribute('href')
  const loc = new URL(url, location.protocol + '//' + location.host)
  const absoluteUrl = loc.toString()

  const cached = requestCache.get(absoluteUrl)

  if (cached && cached.ttl > new Date()) {
    return
  }

  const requestOptions = {
    credentials: 'same-origin',
    headers: { Accept: 'text/html, application/xhtml+xml', 'VND.PREFETCH': 'true', 'X-Turbo': 'true' },
    method: 'GET',
    redirect: 'follow'
  }

  if (linkElement.dataset.turboFrame && linkElement.dataset.turboFrame !== '_top') {
    requestOptions.headers['Turbo-Frame'] = linkElement.dataset.turboFrame
  } else if (linkElement.dataset.turboFrame !== '_top') {
    const turboFrame = linkElement.closest('turbo-frame')

    if (turboFrame) {
      requestOptions.headers['Turbo-Frame'] = turboFrame.id
    }
  }

  requestCache.set(absoluteUrl, { request: fetch(absoluteUrl, requestOptions), ttl: new Date(new Date().getTime() + cacheTtl) })
}

function turboBeforeFetchRequest (event) {
  if (event.target.tagName !== 'FORM' && event.detail.fetchOptions.method === 'GET') {
    const cached = requestCache.get(event.detail.url.toString())

    if (cached && cached.ttl > new Date()) {
      event.detail.response = cached.request
    }
  }

  requestCache.clear()
}

function start () {
  if (!window.turboInstantClickEnabled) {
    document.addEventListener('turbo:before-fetch-request', turboBeforeFetchRequest)
    document.addEventListener('mouseover', mouseoverListener, { capture: true, passive: true })
  }

  window.turboInstantClickEnabled = true
}

export { start }
