<template>
  <component
    :is="component"
    v-model="model"
    v-bind="{ ...$attrs, ...componentProps }"
    :placeholder="placeholder ? placeholder : label"
    :has-error="!!errorMessage"
    :error-message="errorMessage"
    :label="label"
    :is-required="!hideAsterisk && isRequired"
    @blur="onBlur"
  >
    <slot v-if="$slots.default" />
    <span v-else v-text="label" />
  </component>
</template>

<script lang="ts">
import { PropType } from 'vue'
import { Validator } from '../_validators/validators'

type Value = string | number | boolean | Validator<string>[]

export const name = 'KaFormField'

export default {
  name,

  props: {
    type: {
      type: String,
      validator: (v: string) =>
        ['text', 'radio', 'checkbox', 'select'].includes(v),
      default: 'text',
    },
    value: {
      type: [String, Number, Boolean] as PropType<Value>,
      required: true,
    },
    radioValue: {
      type: [String, Number, Boolean] as PropType<Value>,
      default: null,
    },
    label: {
      type: String as PropType<Value>,
      default: '',
    },
    placeholder: {
      type: String as PropType<Value>,
      default: '',
    },
    isRequired: {
      type: Boolean,
      default: false,
    },
    hideAsterisk: {
      type: Boolean,
      default: false,
    },
    validators: {
      type: [] as PropType<Validator<string>[]>,
      default: () => [],
    },
  },
  data() {
    return {
      hasBeenBlurred: false,
    }
  },
  computed: {
    validatorList(): Validator<string>[] {
      if (this.value) return this.validators
      if (this.isRequired)
        return [(value: Value) => (value ? '' : 'error-required')]
      return []
    },
    component(): string {
      switch (this.type) {
        case 'radio':
          return 'ma-option'
        case 'checkbox':
          return 'ma-option'
        case 'select':
          return 'ma-select'
      }
      return 'ma-text-field'
    },
    errorMessages(): string[] {
      return this.validatorList
        .map((validator) => validator(this.model as string))
        .filter((v) => v)
    },
    hasError(): boolean {
      return !!this.errorMessages.length
    },
    errorMessage(): string {
      if (!this.hasBeenBlurred || !this.hasError) return ''
      const [errorMessage] = this.errorMessages
      return this.$t(errorMessage) as string
    },
    model: {
      get(): Value {
        return this.value
      },
      set(value: Value) {
        this.$emit('input', value)
      },
    },
    componentProps(): Record<string, Value> {
      if (this.type === 'radio') {
        return { ...this.$props, value: this.radioValue }
      }
      return { ...this.$props }
    },
  },
  methods: {
    onBlur(): void {
      this.hasBeenBlurred = true
    },
  },
  i18n: {
    messages: {
      es: {
        'error-required': 'Este campo es obligatorio',
        'error-phone-invalid': 'Este teléfono no es correcto',
        'error-email-invalid': 'Este email no es correcto',
      },
      ca: {
        'error-required': 'Aquest camp és obligatori',
        'error-phone-invalid': 'Aquest telèfon no és correcte',
        'error-email-invalid': 'Aquest email no és correcte',
      },
      en: {
        'error-required': 'This field is required',
        'error-phone-invalid': 'This phone is not valid',
        'error-email-invalid': 'This email is not valid',
      },
    },
  },
}
</script>
