require('./dtsel')
const FileUpload = require('./fileupload')
const PageTree = require('../page_tree')
const Fileinfo = require('../fileinfo')
const api = require('../api')
const Editor = require('./editor')
const Dialogue = require('./dialogue')

const EditArticle = {

  oninit: function(vnode) {
    this.loading = false
    this.showLoading = null
    this.data = {
      article: null,
      files: [],
      staff: [],
    }
    this.pages = [{id: null, name: 'Frontpage'}]
    this.pages = this.pages.concat(PageTree.getFlatTree())

    this.removeBanner = false
    this.removeMedia = false
    this.newBanner = null
    this.newMedia = null
    this.dateInstance = null
    this.editor = null

    this.fetchArticle(vnode)
  },

  onbeforeupdate: function(vnode) {
    if (this.lastid !== m.route.param('id')) {
      this.fetchArticle(vnode)
    }
  },

  fetchArticle: function(vnode) {
    this.lastid = m.route.param('id')

    return this.requestArticle(
      api.sendRequest({
        method: 'GET',
        url: '/api/auth/articles/' + (this.lastid === 'add' ? '0' : this.lastid),
      })
    )
  },

  requestArticle: function(data) {
    this.error = ''

    if (this.showLoading) {
      clearTimeout(this.showLoading)
    }

    if (this.data.article) {
      this.showLoading = setTimeout(() => {
        this.showLoading = null
        this.loading = true
        m.redraw()
      }, 150)
    } else {
      this.loading = true
    }

    data
    .then((result) => {
      this.data = result

      if (this.data.article.id) {
        this.data.article.publish_at = new Date(this.data.article.publish_at)
        document.title = 'Editing: ' + this.data.article.name + ' - Admin NFP Moe'
        this.editedPath = true
      } else {
        this.data.article.publish_at = new Date('3000-01-01')
        document.title = 'Create Article - Admin NFP Moe'
      }
    }, (err) => {
      this.error = err.message
    })
    .then(() => {
      clearTimeout(this.showLoading)
      this.showLoading = null
      this.loading = false
      m.redraw()
    })
  },

  updateValue: function(name, e) {
    if (name === 'is_featured') {
      this.data.article[name] = e.currentTarget.checked
    } else {
      this.data.article[name] = e.currentTarget.value
    }
    if (name === 'path') {
      this.editedPath = true
    } else if (name === 'name' && !this.editedPath) {
      this.data.article.path = this.data.article.name
        .normalize("NFD").replace(/[\u0300-\u036f]/g, '')
        .toLocaleLowerCase()
        .replace(/[^a-z0-9]/g, '-')
        .replace(/\-{2,}/g, '-')
        .replace(/^-+/, '')
        .replace(/-+$/, '')
    }
  },

  updateParent: function(e) {
    this.data.article.page_id = Number(e.currentTarget.value) || null
  },

  updateStaffer: function(e) {
    this.data.article.admin_id = Number(e.currentTarget.value)
  },

  mediaUploaded: function(type, file) {
    if (type === 'banner') {
      this.newBanner = file
      this.removeBanner = false
    } else {
      this.newMedia = file
      this.removeMedia = false
    }
  },

  mediaRemoved: function(type) {
    this.data.article[type + '_alt_prefix'] = null
    if (type === 'banner') {
      this.removeBanner = true
    } else {
      this.removeMedia = true
    }
  },

  save: function(vnode, e) {
    e.preventDefault()
    if (!this.data.article.name) {
      this.error = 'Name is missing'
    } else if (!this.data.article.path) {
      this.error = 'Path is missing'
    } else {
      this.error = ''
    }
    if (this.error) return

    let formData = new FormData()
    if (this.newBanner) {
      formData.append('banner', this.newBanner.file)
    }
    if (this.newMedia) {
      formData.append('media', this.newMedia.file)
    }
    if (this.data.article.id) {
      formData.append('id', this.data.article.id)
    }

    formData.append('admin_id', this.data.article.admin_id || this.data.staff[0].id)
    formData.append('name', this.data.article.name)
    formData.append('is_featured', this.data.article.is_featured || false)
    formData.append('path', this.data.article.path)
    formData.append('page_id', this.data.article.page_id || null)
    formData.append('publish_at', this.dateInstance.inputElem.value.replace(', ', 'T') + 'Z')
    formData.append('remove_banner', this.removeBanner ? true : false)
    formData.append('remove_media', this.removeMedia ? true : false)

    this.loading = true

    this.requestArticle(
      this.editor.save()
      .then(body => {
        formData.append('content', JSON.stringify(body))

        return api.sendRequest({
          method: 'PUT',
          url: '/api/auth/articles/' + (this.lastid === 'add' ? '0' : this.lastid),
          body: formData,
        })
      })
      .then(data => {
        if (!data.article.id) {
          throw new Error('Something went wrong with saving, try again later')
        } else if (this.lastid === 'add') {
          this.lastid = data.article.id.toString()
          m.route.set('/admin/articles/' + data.article.id)
        }
        return data
      })
    )
  },

  uploadFile: function(vnode, e) {
    if (!e.target.files[0]) return
    if (this.lastid === 'add') return

    let file = e.target.files[0]
    e.target.value = null

    let formData = new FormData()
    formData.append('file', file)

    return this.refreshFiles(vnode, api.sendRequest({
      method: 'POST',
      url: '/api/auth/articles/' + this.lastid + '/files',
      body: formData,
    }))
  },

  refreshFiles: function(vnode, prom) {
    this.loading = true
    m.redraw()

    prom.then(() => {
      return api.sendRequest({
        method: 'GET',
        url: '/api/auth/articles/' + this.lastid,
      })
    })
    .then((result) => {
      this.data.files = result.files
    }, (err) => {
      this.error = err.message
    })
    .then(() => {
      this.loading = false
      m.redraw()
    })
  },

  confirmRemoveFile: function(vnode, file) {
    return this.refreshFiles(vnode, api.sendRequest({
      method: 'DELETE',
      url: '/api/auth/articles/' + this.lastid + '/files/' + file.id,
    }))
  },

  askConfirmRemoveFile: function(vnode, file) {
    Dialogue.showDialogue(
      'Delete file',
      'Are you sure you want to remove "' + file.filename + '"',
      'Delete',
      'alert',
      'Don\'t delete',
      '',
      file,
      this.confirmRemoveFile.bind(this, vnode))
  },

  view: function(vnode) {
    let article = this.data.article
    const showPublish = article
      ? article.publish_at > new Date()
      : false
    const bannerImage = article && article.banner_alt_prefix
      ? article.banner_alt_prefix + '_large.avif'
      : null
    const mediaImage = article && article.media_alt_prefix
      ? article.media_alt_prefix + '_large.avif'
      : null

    return [
      m('div.admin', [
        !this.loading
          ? m(FileUpload, {
              class: 'banner',
              height: 150,
              onfile: this.mediaUploaded.bind(this, 'banner'),
              ondelete: this.mediaRemoved.bind(this, 'banner'),
              media: bannerImage,
            }, 'Click to upload banner image (only visible when featured)')
          : null,
        m('div.inside.vertical', [
          m('div.actions', [
            '« ',
            m(m.route.Link, { href: '/admin/articles' }, 'Articles'),
            article && article.id
              ? [
                  m('div.filler'),
                  m('span', 'Actions:'),
                  m(m.route.Link, { href: '/article/' + article.path }, 'View article'),
                ]
              : null,
          ]),
          m('h2.title', this.lastid === 'add' ? 'Create article' : 'Edit ' + (article && article.name || '(untitled)')),
          m('div.container', [
            m('div.error', {
              hidden: !this.error,
              onclick: function() { vnode.state.error = '' },
            }, this.error),
            this.loading
              ? m('div.loading-spinner')
              : null,
            article
              ? [
                  m(FileUpload, {
                    class: 'cover',
                    useimg: true,
                    onfile: this.mediaUploaded.bind(this, 'media'),
                    ondelete: this.mediaRemoved.bind(this, 'media'),
                    media: mediaImage,
                  }, 'Click to upload article image'),
                  m('form', {
                    onsubmit: this.save.bind(this, vnode),
                  }, [
                    m('label', 'Parent'),
                    m('select', {
                      onchange: this.updateParent.bind(this),
                    }, this.pages.map((item) => {
                        return m('option', {
                          value: item.id || 0,
                          selected: item.id === article.page_id
                        }, item.name)
                      })),
                    m('div.input-row', [
                      m('div.input-group', [
                        m('label', 'Name'),
                        m('input', {
                          type: 'text',
                          value: article.name,
                          oninput: this.updateValue.bind(this, 'name'),
                        }),
                      ]),
                      m('div.input-group', [
                        m('label', 'Path'),
                        m('input', {
                          type: 'text',
                          value: article.path,
                          oninput: this.updateValue.bind(this, 'path'),
                        }),
                      ]),
                    ]),
                    m('label', 'Description'),
                    m(Editor, {
                      oncreate: (subnode) => {
                        this.editor = subnode.state.editor
                      },
                      contentdata: article.content,
                    }),
                    m('div.input-row', [
                      m('div', [
                        m('label', 'Published at'),
                        m('input', {
                          type: 'text',
                          oncreate: (div) => {
                            if (!this.dateInstance) {
                              this.dateInstance = new dtsel.DTS(div.dom, {
                                dateFormat: 'yyyy-mm-dd',
                                timeFormat: 'HH:MM:SS',
                                showTime: true,
                              })
                              window.temp = this.dateInstance
                            }
                          },
                          value: article.publish_at.toISOString().replace('T', ', ').split('.')[0],
                        }),
                      ]),
                      m('div', [
                        m('label', 'Published by'),
                        m('select', {
                            onchange: this.updateStaffer.bind(this),
                          },
                          this.data.staff.map((item) => {
                            return m('option', {
                              value: item.id,
                              selected: item.id === article.admin_id
                            }, item.name)
                          })
                        ),
                      ]),
                      m('div.slim', [
                        m('label', 'Make featured'),
                        m('input', {
                          type: 'checkbox',
                          checked: article.is_featured,
                          oninput: this.updateValue.bind(this, 'is_featured'),
                        }),
                      ]),
                    ]),
                    m('div.actions', {
                      hidden: !article.name || !article.path
                    }, [
                      m('input', {
                        type: 'submit',
                        value: article.id ? 'Save' : 'Create',
                      }),
                      showPublish
                        ? m('button', {
                            onclick: () => {
                              this.dateInstance.inputElem.value = (new Date().toISOString()).replace('T', ', ').split('.')[0]
                            }
                          }, 'Publish now')
                        : null,
                    ]),
                  ]),
                  m('files', [
                    m('h5', 'Files'),
                    this.data.files.map((file) => {
                      return m(
                        Fileinfo,
                        { file: file },
                        m('div.remove',
                          m('button', { onclick: () => this.askConfirmRemoveFile(vnode, file) }, 'remove')
                        )
                      )
                    }),
                  ]),
                  article.id
                    ? m('div.actions', [
                        m('button.fileupload', [
                          'Add file',
                          m('input', {
                            accept: '*',
                            type: 'file',
                            onchange: this.uploadFile.bind(this, vnode),
                          }),
                        ])
                      ])
                    : null,
                ]
              : null,
          ]),
        ]),
      ]),
    ]
  },
}

module.exports = EditArticle
