import text from './fields/text.js'
import textarea from './fields/textarea.js'
import date from './fields/date.js'
import image from './fields/image.js'
import url from './fields/url.js'
import file from './fields/file.js'
import champs_mail from './fields/champs_mail.js'
import select from './fields/select.js'
import checkbox_group from './fields/checkbox-group.js'
import radio_group from './fields/radio-group.js'
import map from './fields/map.js'
import tags from './fields/tags.js'
import labelhtml from './fields/labelhtml.js'
import titre from './fields/titre.js'
import bookmarklet from './fields/bookmarklet.js'
import conditionschecking from './fields/conditionschecking.js'
import calc from './fields/calc.js'
import reactions from './fields/reactions.js'
import inscriptionliste from './fields/inscriptionliste.js'
import utilisateur_wikini from './fields/utilisateur_wikini.js'
import acls from './fields/acls.js'
import metadatas from './fields/metadatas.js'
import listefichesliees from './fields/listefichesliees.js'
import custom from './fields/custom.js'
import tabs from './fields/tabs.js'
import tabchange from './fields/tabchange.js'
import openinghours from './fields/openinghours.js'

import {
  parseWikiTextIntoJsonData,
  formatJsonDataIntoWikiText
} from './yeswiki-syntax-converter.js'
import {
  copyMultipleSelectValues,
  mapFieldsConf,
  addAdvancedAttributesSection,
  adjustDefaultAcls,
  adjustJqueryBuilderUI,
  convertToBytes
} from './form-builder-helper.js'
import { initListOrFormIdAttribute } from './attributes/list-form-id-attribute.js'
import I18nOption from './i18n.js'

const $formBuilderTextInput = $('#form-builder-text')
window.formBuilder = undefined
window.defaultImage = {}

// Use window to make it available outside of module, so extension can adds their own fields
window.formBuilderFields = {
  text,
  textarea,
  image,
  url,
  file,
  champs_mail,
  select,
  'checkbox-group': checkbox_group,
  'radio-group': radio_group,
  date,
  openinghours,
  map,
  tags,
  labelhtml,
  titre,
  listefichesliees,
  conditionschecking,
  calc,
  reactions,
  inscriptionliste,
  utilisateur_wikini,
  acls,
  metadatas,
  tabs,
  tabchange,
  bookmarklet,
  custom
}

function initializeFormbuilder() {
  // Define an entire group of fields to be added to the stage at a time.
  const inputSets = Object.values(formBuilderFields)
    .map((conf) => conf.set)
    .filter((f) => !!f)

  const typeUserEvents = {}
  Object.keys(formBuilderFields).forEach((field) => {
    typeUserEvents[field] = { onclone: copyMultipleSelectValues }
  })

  // FormBuilder conf
  formBuilder = $('#form-builder-container').formBuilder({
    showActionButtons: false,
    fields: Object.values(formBuilderFields)
      .map((conf) => conf.field)
      .filter((f) => !!f),
    controlOrder: Object.keys(formBuilderFields),
    typeUserAttrs: mapFieldsConf((conf) => conf.attributes),
    typeUserDisabledAttrs: mapFieldsConf((conf) => conf.disabledAttributes),
    typeUserEvents,
    inputSets,
    templates: mapFieldsConf((conf) => conf.renderInput),
    i18n: {
      locale: I18nOption[wiki.locale] ?? 'fr-FR',
      location: `${wiki.baseUrl.replace('?', '')}javascripts/vendor/formbuilder-languages/`
    },
    // Disable some default fields of Jquery formBuilder
    disableFields: [
      'number',
      'button',
      'autocomplete',
      'checkbox',
      'paragraph',
      'header',
      'textarea',
      'checkbox-group',
      'radio-group',
      'select',
      'hidden'
    ],
    // disbale some default attributes of Jquery formBuilder for all fields
    disabledAttrs: [
      'access',
      'placeholder',
      'className',
      'inline',
      'toggle',
      'description',
      'other',
      'multiple'
    ],
    onAddField(fieldId, field) {
      adjustDefaultAcls(field)

      // strange bug with jQuery Formbuilder, the fieldId given is not the last field, but
      // the one just before... so incrementing the id manually
      // transform frmb-XXXX-fld-6  into frmb-XXXX-fld-7
      fieldId = fieldId.replace(
        /(.*)-fld-(\d+)$/gim,
        (string, formId, fieldId) => `${formId}-fld-${parseInt(fieldId, 10) + 1}`
      )

      // Timeout to wait the field ot be rendered
      setTimeout(() => {
        const $field = $(`#${fieldId}`)
        addAdvancedAttributesSection($field)
        initListOrFormIdAttribute($field)
        adjustJqueryBuilderUI($field)

        // disable bf_titre identifier edition
        $field.find('.fld-name').each(function() {
          if ($(this).val() === 'bf_titre') {
            $(this).attr('disabled', true)
          }
        })
      }, 0)
    },
    onOpenFieldEdit() {
      // Labels need to replace <br/> with \n
      $('.fld-content_saisie, .fld-content_display').each((idx, labelElem) => {
        labelElem.value = labelElem.value.replaceAll('<br/>', '\n')
      })
      // Default image is in base64 in buffer variable => convert it to File in input element
      $('input.default-file').each((idx, file_elem) => {
        const current_ids = file_elem.attributes.id.value.split('-')
        const image_name = `${current_ids[current_ids.length - 2]}-${current_ids[current_ids.length - 1]}`
        if (window.defaultImage[image_name]) {
          const image_content = window.defaultImage[image_name].split('|')
          if (image_content.length === 2) {
            const dataTransfer = new DataTransfer()
            dataTransfer.items.add(
              new File(convertToBytes(image_content[1]), image_content[0])
            )
            file_elem.files = dataTransfer.files
          }
        }
        if (file_elem.parentElement.childElementCount == 1) {
          const new_button = document.createElement('i')
          new_button.className = 'fas fa-remove btn-img-remove'
          new_button.onclick = function() {
            file_elem.files = new DataTransfer().files
            window.defaultImage[image_name] = ''
          }
          file_elem.parentElement.append(new_button)
        }
      })
      // When change image, save it to base64 to buffer variable
      $('input.default-file').change((event) => {
        const current_ids = event.target.attributes.id.value.split('-')
        const image_name = `${current_ids[current_ids.length - 2]}-${current_ids[current_ids.length - 1]}`
        const file = event.target.files[0]
        if (typeof imageMaxSize == 'undefined') {
          var imageMaxSize = 1024 * 1024
        }
        if (file.size > imageMaxSize) {
          alert(_t('IMAGEFIELD_TOO_LARGE_IMAGE', { imageMaxSize }))
          event.target.value = ''
          return false
        }
        const reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onload = function() {
          window.defaultImage[image_name] = `${file.name}|${reader.result}`
        }
      })
    }
  })

  const defaultFieldsName = mapFieldsConf((conf) => conf.defaultIdentifier)

  let formBuilderInitialized = false
  let existingFieldsNames = []
  let existingFieldsIds = []

  setInterval(() => {
    if (!formBuilder || !formBuilder.actions || !formBuilder.actions.setData) return
    if (!formBuilderInitialized) {
      initializeBuilderFromTextInput()
      existingFieldsIds = getFieldsIds()
      formBuilderInitialized = true
    }
    if ($formBuilderTextInput.is(':focus')) return

    existingFieldsNames = []
    $('.fld-name').each(function() {
      existingFieldsNames.push($(this).val())
    })

    // Slugiy field names
    $('.fld-name').each(function() {
      const newValue = $(this)
        .val()
        .replace(/[^a-z^A-Z^_^0-9^{^}]/g, '_')
      $(this).val(newValue)
    })

    // Update the text field converting form builder content into wiki syntax
    if ($('#form-builder-container').is(':visible')) {
      const formData = formBuilder.actions.getData()
      // save base64 default image from buffer variable
      Object.keys(window.defaultImage).forEach((image_name) => {
        if (
          window.defaultImage[image_name]
          && window.defaultImage[image_name] != ''
        ) {
          const image_names = image_name.split('-')
          const field_idx = Number(image_names[image_names.length - 1]) - 1
          formData[field_idx].default_image = window.defaultImage[image_name]
        }
      })
      const wikiText = formatJsonDataIntoWikiText(formData)
      if (wikiText) $formBuilderTextInput.val(wikiText)
    }

    $('.fld-name').each(function() {
      let name = $(this).val()
      const id = $(this).closest('.form-field').attr('id')

      // Detect new fields added
      if (!existingFieldsIds.includes(id)) {
        const fieldType = $(this).closest('.form-field').attr('type')

        // Make the default names easier to read
        if (!name.includes('bf_')) {
          name = defaultFieldsName[fieldType] || `bf_${fieldType}`
          if (existingFieldsNames.includes(name)) {
            // If name already exist, we add a number (bf_address, bf_address1, bf_address2...)
            let number = 1
            while (existingFieldsNames.includes(name + number)) number += 1
            name += number
          }
        }

        // if it's a map, we automatically add a bf_addresse
        if (fieldType == 'map' && !existingFieldsNames.includes('bf_adresse')) {
          const field = {
            type: 'text',
            subtype: 'text',
            name: 'bf_adresse',
            label: _t('BAZ_FORM_EDIT_ADDRESS')
          }
          const index = $(this).closest('.form-field').index()
          formBuilder.actions.addField(field, index)
        }
      }
      $(this).val(name)
    })

    existingFieldsIds = getFieldsIds()

    // Transform input[textarea] in real textarea
    $('input[type="textarea"]').replaceWith(function() {
      const domTextarea = document.createElement('textarea')
      domTextarea.id = this.id
      domTextarea.name = this.name
      domTextarea.value = this.value
      domTextarea.classList = this.classList
      domTextarea.title = this.title
      domTextarea.rows = $(this).attr('rows')
      return domTextarea
    })

    $('.text-field select[name=subtype]:not(.initialized)')
      .on('change', function() {
        $(this).addClass('initialized')
        const $parent = $(this).closest('.form-field')
        if ($(this).val() == 'range' || $(this).val() == 'number') {
          $parent
            .find('.maxlength-wrap label')
            .text(_t('BAZ_FORM_EDIT_MAX_VAL'))
          $parent.find('.size-wrap label').text(_t('BAZ_FORM_EDIT_MIN_VAL'))
        } else {
          $parent
            .find('.maxlength-wrap label')
            .text(_t('BAZ_FORM_EDIT_MAX_LENGTH'))
          $parent.find('.size-wrap label').text(_t('BAZ_FORM_EDIT_NB_CHARS'))
        }
        if ($(this).val() == 'color') {
          $parent.find('.maxlength-wrap, .size-wrap').hide()
        } else {
          $parent.find('.maxlength-wrap, .size-wrap').show()
        }
      })
      .trigger('change')

    // in semantic field, we want to separate value by coma
    $('.fld-semantic').each(function() {
      let newVal = $(this)
        .val()
        .replace(/\s*,\s*/g, ',')
      newVal = newVal.replace(/\s+/g, ',')
      newVal = newVal.replace(/,+/g, ',')
      $(this).val(newVal)
    })
  }, 300)

  $('#formbuilder-link').click(initializeBuilderFromTextInput)
}

document.addEventListener('DOMContentLoaded', () => {
  initializeFormbuilder()
})

function getFieldsIds() {
  const result = []
  $('.fld-name').each(function() {
    result.push($(this).closest('.form-field').attr('id'))
  })
  return result
}

function initializeBuilderFromTextInput() {
  const jsonData = parseWikiTextIntoJsonData($formBuilderTextInput.val())
  try {
    window.defaultImage = {}
    // extract base64 default image to buffer variable
    jsonData.forEach((field, index) => {
      if (field.type === 'image') {
        window.defaultImage[`fld-${index + 1}`] = field.default_image.trim()
      }
    })
    formBuilder.actions.setData(JSON.stringify(jsonData))
  } catch (error) {
    console.error(error)
  }
}

$('a[href="#formbuilder"]').on('click', (event) => {
  if (!confirm(_t('BAZ_FORM_EDIT_CONFIRM_DISPLAY_FORMBUILDER'))) {
    event.preventDefault()
    return false
  }
})
