import Templates from '../templates/Views'
import { createNode, destroyNode, findDates, formatDate, parseURL, replaceURLPathname, ucWords } from '../helpers'
import NotesAPI from './NotesAPI'
import ValidationController from './ValidationController'
import Alert from './AlertController'

export default class DOMController {

  constructor (root, routes) {
    this.routes = routes
    this.root = root

    try {
      this.root.innerHTML = Templates.grid
      this.renderRoutes()
    } catch (e) {
      Alert.displayDialog(e.toString(), 0, 3)
    }

    this.btnCreateNote = this.root.querySelector(window.env.querySelectors.btnCreateNote)
    this.btnPrepopulate = this.root.querySelector(window.env.querySelectors.btnPrepopulate)
    this.createNotesGrid(window.env.prePopulateAmount || 0)

    this.listener([
      [this.btnCreateNote, 'click', (this.btnCreateNote.dataset.action || 'showError'), { legend: 'Create Note' }],
      [this.btnPrepopulate, 'click', (this.btnPrepopulate.dataset.action || 'showError')],
    ])

  }

  /**
   *
   */
  renderRoutes () {

    for (const [route, name] of Object.entries(this.routes.routes)) {

      const tab = createNode('li')
      tab.classList.add('nav-tab')

      if (route === '/') {
        tab.classList.add('initial')
        tab.classList.add('uk-active')
      }

      tab.innerHTML = `<a href="${route}">${name}</a>`
      const anchor = tab.querySelector('a')
      this.routes.navbar.appendChild(tab)

      this.listener([anchor, 'click', 'createNotesGridByRoute', anchor])
    }
  }

  createNotesGridByRoute (navTab) {
    const pathname = parseURL(navTab.href).pathname
    const route = pathname.slice(1).split('\/')[0]
    window.history.pushState('', navTab.innerText, pathname) //change url without reload
    //history.pushState({}, null, pathname) //change url

    this.routes.navbar.querySelector('.uk-active').classList.remove('uk-active')
    navTab.closest('.nav-tab').classList.add('uk-active')

    document.getElementById(window.env.querySelectors.analyticsGrid.slice(1)).classList.add('uk-hidden')
    document.getElementById(window.env.querySelectors.notesGrid.slice(1)).classList.remove('uk-hidden')

    switch (route) {
      case 'all':
        this.createNotesGrid(0, null)
        break
      case '':
        this.createNotesGrid(window.env.prePopulateAmount || 0)
        break
      case 'archive':
        this.createNotesGrid(window.env.prePopulateAmount || 0, true)
        break
      case 'analytics':
        document.getElementById(window.env.querySelectors.notesGrid.slice(1)).classList.add('uk-hidden')
        const analyticsGrid =   document.getElementById(window.env.querySelectors.analyticsGrid.slice(1))
        this.createAnalyticsGrid(analyticsGrid)
        break
    }
  }

  prePopulate () {
    const fakerAmount = document.querySelector(env.querySelectors.selectPrepopulate)

    if (+fakerAmount.value <= 0) {
      return
    }
    env.fakerAmount = (+fakerAmount.value > 44) ? 44 : +fakerAmount.value
    localStorage.removeItem(window.env.localStorageKey)
    fakerAmount.selectedIndex = 0
    document.querySelector('.nav-tab.uk-active > a').click()

  }

  /**
   * The method is being called for typical DOM-event task inside the table row
   * to manipulate with records: deleting, editing, archiving.
   *
   * @param node
   * @param method
   */
  noteToAction (node, method) {

    const row = node.closest('tr')

    NotesAPI[method](parseInt(row.dataset.id, 10))
    row.classList.add('as-removing')

    setTimeout(() => {
      row.remove()
      document.querySelector('.nav-tab.uk-active > a').click()
    }, 1050)
  }

  /**
   *
   * @param node
   */
  noteToArchive (node) {
    this.noteToAction(node, 'archiveNote')
  }

  /**
   *
   * @param node
   */
  noteFromArchive (node) {
    this.noteToAction(node, 'unArchiveNote')
  }

  /**
   *
   * @param node
   */
  noteToTrash (node) {
    this.noteToAction(node, 'deleteNote')
  }

  createAnalyticsGrid (grid) {
    grid.classList.remove('uk-hidden')
    const aGrid = grid.querySelector(' tbody')
    aGrid.innerHTML = ''

    for (const [key, value] of Object.entries(NotesAPI.getAnalytics())) {

      const row = createNode('tr')
      const td = createNode('td', {}, ucWords(key))
      row.appendChild(td)

      for (const [key, val] of Object.entries( value ) ) {
        const td = createNode('td', {}, val.toString())
        row.appendChild(td)
      }

      aGrid.appendChild(row)
    }
  }

  /**
   *
   * @param len
   * @param archived
   */
  createNotesGrid (len = window.env.prePopulateAmount || 0, archived = false) {

    const notesGrid = document.querySelector(window.env.querySelectors.notesGrid + ' tbody')
    notesGrid.innerHTML = ''

    const notes = NotesAPI.getNotesSanitized(len, archived)
    if (notes.length === 0) { return }

    notes.forEach(el => {

      const row = createNode('tr')
      row.dataset.id = el.id

      window.env.gridOrder.notes.forEach(key => {
        let attrs = {}
        let value = el[key] || ''

        switch (key) {
          case 'createdAt':
            value = formatDate(value)
            break
          case 'category':
            value = ucWords(value)
            break
          case 'title':
            attrs.class = 'uk-text-bold'
            break
          case 'dates':
            attrs.style = 'font-size: 12px'
            value = findDates(el.content).join(', ')
            break
          case 'edit' :
            attrs.class = 'grid-control icon icon-edit'
            attrs['data-action'] = 'getEditForm'
            break
          case 'archive' :
            attrs.class = 'grid-control icon ' + (value === 'on' ? 'icon-unarchive' : 'icon-archive')
            attrs['data-action'] = value === 'on' ? 'noteFromArchive' : 'noteToArchive'
            value = ''
            break
          case 'delete' :
            attrs.class = 'icon icon-delete grid-control'
            attrs['data-action'] = 'noteToTrash'
            break
        }

        const td = createNode('td', attrs, value)

        if (key.match(/^(edit|archive|delete)$/)) {
          this.listener([td, 'click', td.dataset.action, td])
        }

        row.appendChild(td)

      })
      notesGrid.appendChild(row)
    })
  }

  /**
   *
   * @param selector
   * @returns {{}}
   */
  static getFormData (selector = window.env.querySelectors.noteEditForm) {
    const formData = new FormData(document.querySelector(selector))
    const data = {}

    for (let key of formData.keys()) {
      data[key] = formData.get(key)
    }
    return data
  }

  /**
   *
   * @param args
   */
  getEditForm (args = {}) {

    const node = createNode('div', { class: window.env.querySelectors.modal.slice(1) },
      Templates.templates.editForm)

    if (args.legend) {
      node.querySelector('legend').innerHTML = args.legend
    } else {
      DOMController.fillTheForm(node, args)
    }

    this.root.appendChild(node)
    node.style.display = 'block'

    const contentInput = node.querySelector('textarea[maxlength]')
    const titleInput = node.querySelector('input[maxlength]')

    this.listener([
      [node.querySelector(window.env.querySelectors.btnDestroyModal), 'click', destroyNode, node], //Remove modal dialog
      [node.querySelector('form'), 'submit', NotesAPI.saveNote],
      [contentInput, 'keydown', ValidationController.lengthOnKeyUp, contentInput],
      [titleInput, 'keydown', ValidationController.lengthOnKeyUp, titleInput],
    ])
  }

  /**
   *
   * @param $form
   * @param $el
   */
  static fillTheForm ($form, $el) {
    if ($el instanceof Element) {
      const note = NotesAPI.getNoteByID(+$el.closest('tr').dataset.id)

      if (note.length === 1) {
        for (const [key, value] of Object.entries(note[0])) {
          const $input = $form.querySelector(`[name='${key}']`)

          if ($input instanceof Element) {

            if ($input.type === 'checkbox') {

              if (value !== '') {
                $input.click()
              }

            } else {
              $input.value = value
            }
          }
        }
      }
    }
  }

  /**
   * The function takes single DOM element or list of them
   *
   * @param els
   * @returns {void|*}
   */
  listener (els) { return els[0] instanceof Element ? this.on(els) : els.forEach(el => this.on(el)) }

  /**
   * TODO: guessed this should be rethought
   * @param args
   */
  on (args) {

    const [selector, event, method] = args

    if (!(selector instanceof Element)) {
      Alert.displayDialog(`Internal Error: Try reload a page`, 3000, 3)
      return false
    }

    try {
      selector.addEventListener(event, evt => {
        const params = args[3] || {}

        if (selector.tagName === 'A') {
          evt.preventDefault()
        }

        if (evt.type === 'submit') {
          evt.preventDefault()

          setTimeout(() => {
            document.querySelector('.nav-tab.uk-active > a').click()
          }, 300)
        }

        if (typeof this[method] === 'function') {
          this[method](params)
        } else if (typeof method === 'function') {
          method(params)
        }
      })

      return true

    } catch (err) {
      Alert.displayDialog(`Error: ${err.toString()}`, 3000, 3)

      return false
    }
  }

}