import { mapActions } from 'vuex'
import element from '@baserow/modules/builder/mixins/element'
import { FormContainerElementType } from '@baserow/modules/builder/elementTypes'

export default {
  mixins: [element],
  data() {
    return {
      inputValue: null,
    }
  },
  computed: {
    formElementData() {
      return this.$store.getters['formData/getFormData'](this.page)[
        this.element.id
      ]
    },
    elementFormDataValue() {
      return this.formElementData?.value
    },
    displayFormDataError() {
      return (
        this.formElementTouched &&
        !this.formElementData?.isValid &&
        !this.isEditMode
      )
    },
    errorMessage() {
      return this.displayFormDataError ? this.getErrorMessage() : ''
    },
    formElementTouched() {
      return this.$store.getters['formData/getElementTouched'](
        this.page,
        this.element.id
      )
    },
    /**
     * Returns whether the form element is a descendant of a form container.
     * @returns {Boolean} If one or more ancestors is a form container.
     */
    isDescendantOfFormContainer() {
      return this.$store.getters['element/getAncestors'](
        this.page,
        this.element
      ).some(({ type }) => type === FormContainerElementType.getType())
    },
  },
  methods: {
    ...mapActions({
      actionSetFormData: 'formData/setFormData',
    }),
    /*
     * When a form element has been modified (e.g. a user has inputted a value),
     * this method is responsible for updating the form data in the store, and
     * if it's not inside a form container, marking the form element as having
     * been 'touched' by the user.
     */
    handleFormElementChange(value) {
      this.setFormData(value)
      if (!this.isDescendantOfFormContainer) {
        this.onFormElementTouch()
      }
    },
    setFormData(value) {
      return this.actionSetFormData({
        page: this.page,
        elementId: this.element.id,
        payload: {
          value,
          touched: this.formElementTouched,
          type: this.elementType.formDataType,
          isValid: this.elementType.isValid(this.element, value),
        },
      })
    },
    /**
     * Responsible for marking this form element as being 'touched' by a
     * user. This will help influence whether to display validation errors.
     */
    onFormElementTouch() {
      this.$store.dispatch('formData/setElementTouched', {
        page: this.page,
        wasTouched: true,
        elementId: this.element.id,
      })
    },
    /** Override this method to display the right error message */
    getErrorMessage() {
      return ''
    },
  },
  watch: {
    /**
     * When a form element's formData value changes.
     */
    elementFormDataValue: {
      handler(newValue) {
        this.inputValue = newValue
      },
      immediate: true,
    },
    inputValue(newValue) {
      this.handleFormElementChange(newValue)
    },
  },
}