import onFind from './onFind'
import debounce from '../util/debounce'
import onVisible from './onVisible'

/*
  Simple string replacement utility.
  Find all instances of "___" in the string
  and replace with each string in the list of data.
  eg:
    template = 'Today is ___ and the weather is ___.'
    data = ['Friday', 'sunnny']
    --------------------------
    <- 'Today is Friday and the weather is sunny.'
*/
export function replaceWithEach(template: string, data: string[]) {
  return template.replace(
    /_{3}/g,
    (
      (i) => (_: string) =>
        data[i++]
    )(0),
  )
}

export function announce(message: string, data?: string[]) {
  let container = document.getElementById('aria-live-container')
  if (!container) {
    container = document.createElement('div')
    container.setAttribute('id', 'aria-live-container')
    document.body.appendChild(container)
  }
  const status = document.createElement('div')
  const id = 'speak-' + Date.now()
  status.setAttribute('id', id)
  status.setAttribute('aria-atomic', 'true')
  status.setAttribute('aria-live', 'polite')
  status.classList.add('screen-reader-only')
  if (data && data.length) {
    message = replaceWithEach(`${message}`, data)
  }
  container.appendChild(status)

  setTimeout(() => {
    const liveRegion = document.getElementById(id)
    if (liveRegion) liveRegion.innerHTML = message
  }, 150)

  if (window.BRIGHTSPOT?.ariaDebug === true) {
    console.log(`ARIA Announced: "${message}"`)
  }

  setTimeout(() => {
    document.getElementById(id)?.remove()
  }, 2000)
}

document.addEventListener('DOMContentLoaded', () => {
  document.body.addEventListener('btu-announce', (event) => {
    if (event instanceof CustomEvent) {
      announce(event.detail)
    }
  })
})

const announcements: HTMLElement[] = []

onFind('[data-aria-announce]', (element: HTMLElement) => {
  announcements.push(element)
  setTimeout(() => {
    if (announcements.length > 0) {
      const message = announcements
        .map((element) =>
          'true' === element.dataset.ariaAnnounce
            ? element.textContent
            : element.dataset.ariaAnnounce,
        )
        .join(', ')
      announcements.length = 0
      announce(message)
    }
  }, 2500)
})

/**
 * Buttons like "Add" or calendar are created on the frontend and bound to hidden input(s).
 * Copy the error message 'id' attribute to set the 'aria-describedby' attribute value to
 * the button.
 */
onVisible(
  [
    '.addButton',
    '.Workflow-addState',
    '.Workflow-addTransition',
    '.calendarButton',
    '.ComboInput',
  ],
  (element: HTMLElement) => {
    const row = element.closest('.CIG-row')
    if (!row) return
    const message = row.querySelector('.Message.is-error')
    if (!message) return
    const id = message.getAttribute('id')
    if (!id) return
    element.setAttribute('aria-describedby', id)
    element.setAttribute('aria-invalid', 'true')
  },
)

/**
 * All anchor tags acting as buttons need to respond to Enter and Space keys.
 */
onVisible('a[role="button"]', (element: HTMLElement) => {
  element.addEventListener('keydown', (event) => {
    if (event.code === 'Space') {
      event.preventDefault()
      element.click()
    }
  })
})

export const announceWithDelay = (message: string) => {
  debounce(1000, () => announce(message))
}
