import { debounce } from './utils.js'

const KEY_TAB = 'Tab'
const KEY_ESC = 'Escape'
const HTTP_METHOD_POST = 'post'
const API_URL = '/.netlify/functions/html2pug'
const DEBOUNCE_MS = 500
const LOADING_TEXT = 'Loading...'
const IS_FRAGMENT_SETTING = 'isFragment'
const ERROR_TEXT = `Oh no! Something went wrong :(

It could be a server fault, or it could be invalid HTML.
Please check your input and try again.`

const state = {
  el: {
    main: null,
    input: null,
    output: null,
    menuBtn: null,
    settingsForm: null,
  },

  settings: {
    useTabs: false,
    useCommas: true,
    isFragment: true,
  },
}

const convertToPug = async (html = '') => {
  // Send HTML to server for conversion
  const res = await fetch(API_URL, {
    method: HTTP_METHOD_POST,
    body: JSON.stringify({ html, settings: state.settings }),
  })

  if (res.status !== 200) {
    throw new Error(ERROR_TEXT)
  }

  const text = await res.text()
  return text
}

const setOutputValue = value => {
  const { output } = state.el
  if (output) {
    output.value = value
  }
}

const indentForward = el => {
  const s = el.selectionStart
  const tab = state.settings.useTabs ? '\t' : ' '.repeat(2)

  const start = el.value.substring(0, s)
  const end = el.value.substring(el.selectionEnd)

  el.value = `${start}${tab}${end}`
  el.selectionEnd = s + tab.length
}

// Save a single settings change to state.
const updateSettingsField = (name, value) => {
  const { settings } = state
  if (Object.keys(settings).includes(name)) {
    settings[name] = value
    window.localStorage.setItem('settings', JSON.stringify(settings))
  }
}

// Save all settings to state and ensure radio inputs match.
const updateSettings = (settings = {}) => {
  state.settings = { ...state.settings, ...settings }

  const { settingsForm } = state.el
  const boolToNumber = bool => (bool ? 1 : 0)

  Object.entries(state.settings).forEach(([key, val]) => {
    switch (key) {
      case IS_FRAGMENT_SETTING:
        return
      default: {
        settingsForm[key].value = boolToNumber(val)
        return
      }
    }
  })
}

const handleInputKeyDown = e => {
  const { key, shiftKey, target: input } = e
  if (key === KEY_TAB) {
    e.preventDefault()
    input.focus()

    if (!shiftKey) {
      return indentForward(input)
    }
  }
}

const handleInputChange = e => {
  const { target: input } = e

  // Do nothing if input is empty
  if (!input.value) {
    return setOutputValue(input.value)
  }

  setOutputValue(LOADING_TEXT)

  return convertToPug(input.value)
    .then(pug => setOutputValue(pug))
    .catch(err => {
      setOutputValue(ERROR_TEXT)
      // eslint-disable-next-line no-console
      console.error(err)
    })
}

const handleSettingsChange = e => {
  const { name, value } = e.target
  // Convert "1"/"0" to true/false
  return updateSettingsField(name, Boolean(parseInt(value, 10)))
}

const handleMenuBtnClick = (showMenu = true) => {
  const { main } = state.el

  if (main.classList.contains('show-menu')) {
    main.classList.remove('show-menu')
  } else if (showMenu) {
    main.classList.add('show-menu')
  }
}

const handleDocumentKeyUp = e => {
  const { key } = e
  if (key === KEY_ESC) {
    handleMenuBtnClick(false)
  }
}

function main() {
  state.el.main = document.getElementById('page')
  state.el.input = document.getElementById('input')
  state.el.output = document.getElementById('output')
  state.el.menuBtn = document.getElementById('menu-btn')
  state.el.settingsForm = document.getElementById('settings')

  const { input, menuBtn } = state.el

  input.addEventListener('keydown', handleInputKeyDown)
  input.addEventListener(
    'input',
    debounce(e => handleInputChange(e), DEBOUNCE_MS)
  )

  menuBtn.addEventListener('click', handleMenuBtnClick)

  // Clear inputs at launch
  document.querySelectorAll('textarea').forEach(input => {
    input.value = ''
  })

  // Get saved preferences from localStorage
  const prefs = JSON.parse(window.localStorage.getItem('settings')) || {}
  updateSettings({ ...state.settings, ...prefs })

  // Listen for changes in settings
  document
    .getElementById('settings')
    .addEventListener('input', handleSettingsChange)

  // Close menu when clicking about link
  document
    .getElementById('about-link')
    .addEventListener('click', handleMenuBtnClick)

  document.addEventListener('keyup', handleDocumentKeyUp)
}

window.addEventListener('load', main)

@@ -620,26 +620,51 @@
 %0A%7D%0A%0A
-const convertToPug
+// Send request to API%0Aconst sendApiRequest
  = a
@@ -672,19 +672,12 @@
 ync 
-(
 html
- = '')
  =%3E 
@@ -963,24 +963,384 @@
 urn text%0A%7D%0A%0A
+const convertToPug = async (html = '') =%3E %7B%0A  // Clear input if value is blank%0A  if (!html.length) %7B%0A    setOutputValue(html)%0A  %7D%0A%0A  setOutputValue(LOADING_TEXT)%0A%0A  try %7B%0A    const pug = await sendApiRequest(html)%0A    setOutputValue(pug)%0A  %7D catch (err) %7B%0A    setOutputValue(ERROR_TEXT)%0A    // eslint-disable-next-line no-console%0A    console.error(err)%0A  %7D%0A%7D%0A%0A
 const setOut
@@ -1796,16 +1796,22 @@
 sField =
+ async
  (name, 
@@ -1840,16 +1840,20 @@
 settings
+, el
  %7D = sta
@@ -1855,16 +1855,17 @@
 = state%0A
+%0A
   if (Ob
@@ -1998,16 +1998,143 @@
 ttings))
+%0A%0A    // Trigger re-complile%0A    const %7B input %7D = el%0A    if (input.value.length) %7B%0A      await convertToPug(input.value)%0A    %7D
 %0A  %7D%0A%7D%0A%0A
@@ -2991,37 +2991,45 @@
 %0A%0A  
-setOutputV
+return convertToPug(input.v
 alue
-(LOADING_TEXT)%0A
+)%0A  /*
 %0A  r
@@ -3225,15 +3225,22 @@
 rr)%0A
-
     %7D)%0A
+    */%0A
 %7D%0A%0Ac

Recompile if settings change