<template>
  <div class="mb-1 row">
    <label v-if="field.type !== 'BooleanField' && showLabel && formStyle != 'floating-labels'" class="col-form-label" :class="labelClass">
      {{label}}
      <em v-if="rules.required" class="text-danger">*</em>
    </label>
    <div :class="showLabel && formStyle != 'floating-labels' ? controlClass : 'col-sm-12'">
      <slot name="input">
        <div v-if="!readonly && !readonlyForm" :class="formStyle=='floating-labels' ? 'form-floating' : ''">
          <SmartSelect v-if="field.has_one"
                       v-model="value"
                       v-tooltip:right="errorMessage"
                       :class="{'is-invalid':errorMessage}"
                       :options="options"
                       :filters="filters"
                       :disabled="disabled"
                       :query="field.has_one.model"
                       :null-description="rules.required ? t('ui.please_select', {field : label}) : t('ui.none')"
                       @update:modelValue="$emit('update:modelValue', $event)">
            <template v-slot:option="item">
              <slot name="option" v-bind:option="item.option"/>
            </template>
          </SmartSelect>
          <SmartSelect v-else-if="field.choices"
                       v-model="value"
                       v-tooltip:right="errorMessage"
                       :class="{'is-invalid': errorMessage}"
                       :options="choices"
                       :disabled="disabled"
                       id-index="0"
                       description-index="1"
                       :null-description="rules.required ? t('ui.please_select', {field : label}) : t('ui.none')"
                       @update:modelValue="$emit('update:modelValue', $event)">
            <template v-slot:option="item">
              <slot name="option" v-bind:option="item.option"/>
            </template>
          </SmartSelect>
          <SmartRte v-else-if="field.type === 'TextField' && rte"
                    v-model="value"
                    v-tooltip:right="errorMessage"
                    :placeholder="formStyle == 'floating-labels' ? label : placeholder"
                    :disabled="disabled"
                    style="height: 20em"
                    class="form-control form-control-sm"
                    :class="{'is-invalid': errorMessage}"
                    @update:modelValue="$emit('update:modelValue', $event)" />
          <textarea v-else-if="field.type === 'TextField' && !rte"
                    v-model="value"
                    v-tooltip:right="errorMessage"
                    :disabled="disabled"
                    :placeholder="formStyle == 'floating-labels' ? label : placeholder"
                    style="height: 20em"
                    class="form-control form-control-sm"
                    :class="{'is-invalid': errorMessage}"
                    @update:modelValue="$emit('update:modelValue', $event)" />
          <div v-else-if="field.type === 'BooleanField'" class="form-check form-switch">
            <input :id="name"
                   :checked="value"
                   type="checkbox"
                   class="form-check-input"
                   :disabled="disabled"
                   :value="true"
                   @change="check(value)">
            <label class="form-check-label" :for="name">{{label}}</label>
          </div>
          <input v-else-if="field.type === 'FileField'"
                 v-tooltip:right="errorMessage"
                 autocomplete="nope"
                 type="file"
                 class="form-control form-control-sm"
                 :disabled="disabled"
                 :placeholder="formStyle == 'floating-labels' ? label : placeholder"
                 :class="{'is-invalid': errorMessage}"
                 @change="handleChange($event);$emit('update:modelValue', $event.target.files[0])" >
          <input v-else
                 v-model="value"
                 v-tooltip:right="errorMessage"
                 autocomplete="nope"
                 type="text"
                 class="form-control form-control-sm"
                 :disabled="disabled"
                 :placeholder="formStyle == 'floating-labels' ? label : placeholder"
                 :class="{'is-invalid': errorMessage}"
                 @update:modelValue="$emit('update:modelValue', $event)" >
          <label v-if="formStyle == 'floating-labels'">{{label}}</label>
          <div class="form-control-action"><slot name="action" /></div>
        </div>
        <div v-else :class="formStyle=='floating-labels' ? 'form-floating' : ''">
          <div readonly :class="formStyle == 'floating-labels' ? 'form-control' : 'form-control-plaintext'" class="form-control-sm">{{valueDescription}}</div>
          <label v-if="formStyle == 'floating-labels'">{{label}}</label>
        </div>
      </slot>
    </div>
  </div>
</template>

<script>
import { watch, inject, computed } from 'vue'
import { useField } from 'vee-validate'

import { useI18n } from 'vue-i18n'

import SmartSelect from '@/components/SmartSelect'
import SmartRte from '@/components/SmartRte'


export default {
  setup(props) {

    const { t } = useI18n()
    const readonlyForm = inject('readonlyForm')
    const definition = inject('definition')
    const labelSize = inject('labelSize')

    const field = definition.fields[props.name]

    const label = t(['models', definition.model, 'fields', props.name, 'name'].join('.'))

    let choices = null
    if(field.choices){
      choices = [...field.choices]
      for (const x in choices) {
        choices[x][1] = t(['models', definition.model, 'fields', props.name, 'choices', choices[x][0]].join('.'))
      }
    }

    const labelClass = 'col-sm-' + labelSize

    let size = 12

    if (field && field.type === 'CharField' && !field.choices) {
      if (field.max_length <= 5) {
        size = 2
      } else if (field.max_length <= 10) {
        size = 3
      } else if (field.max_length <= 20) {
        size = 4

      }
    }

    if (size + labelSize > 12) {
      size = 12 - labelSize
    }

    const controlClass = {}
    controlClass['col-sm-' + size] = true
    if (field.type === 'BooleanField') {
      controlClass['offset-sm-' + (12 - size)] = true
    }

    const rules = computed(() => {
      if(!props.validation){
        const validation = {
          required: !field.blank && field.type !== 'BooleanField' && !field.generated_default,
          integer: !field.choices && (field.type === 'IntegerField' || field.type === 'BigIntegerField'),
          email: field.type === 'EmailField'
        }

        if(['PhoneField', 'FaxField'].includes(field.type)) {
          validation.phone = true
        }

        if(field.type === 'FileField') {
          validation.ext = field.exts
        }

        return validation
      }

      return props.validation
    })

    const { errorMessage, value, handleChange } = useField(props.name, rules, {label: label, initialValue: props.modelValue})

    watch(() => props.modelValue, () => {
      value.value = props.modelValue
    })

    const valueDescription = computed(() => {

      let description = t('ui.na')

      if(props.modelValue){
        description = props.modelValue
        if (field.has_one) {
          description = props.modelValue.node_description
        } else if (field.choices) {
          field.choices.forEach((item) => {
            if(item[0] == props.modelValue){
              description = item[1]
            }
          })
        }
      }

      return description
    })

    return {
      readonlyForm,
      choices,
      labelClass,
      controlClass,
      handleChange,
      errorMessage,
      valueDescription,
      value,
      label,
      field,
      rules,
      t
    }
  },
  props: {
    modelValue: {
      type: [String, Object, Number, Array, Boolean],
      default:null
    },
    readonly: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    rte: {
      type: Boolean,
      default: false
    },
    name: {
      type: String,
      required: true
    },
    placeholder: {
      type: String,
      required: false,
      default:null
    },
    validation: {
      type: Function,
      default:null
    },
    options: {
      type: Array,
      required: false,
      default: function () {
        return []
      }
    },
    formStyle: {
      type: String,
      required: false,
      default:'default'
    },
    showLabel: {
      type: Boolean,
      default: true
    },
    filters: {
      type: Array,
      default: function () {
        return []
      }
    },
  },
  methods: {
    check: function (field) {
      field = !field
      this.$emit('update:modelValue', field)
    }
  },
  components: {SmartSelect, SmartRte},
  emits: ['update:modelValue'],
}
</script>
