<template>
    <label
        :class="[buttonWrapperClasses, { 'has-error': errors.length > 0 &&!suppressError,
        selected: isChecked }]"
        :for="buttonId"
        @focusin="handleFocus"
        @focusout="handleBlur"
        @mousedown.left="handleEventAction(eventTypes.CLICK, $event)">
        <input
            :id="buttonId"
            :key="buttonId"
            :type="inputType"
            :name="groupName"
            :class="inputClasses"
            :aria-required="isRequired"
            :value="value"
            :checked="isChecked"
            @keypress.space="handleEventAction(eventTypes.SPACE, $event)"
            @keypress.enter="handleEventAction(eventTypes.ENTER, $event)"
            @change="handleEventAction(eventTypes.CHANGE, $event)" />

        <slot></slot>
    </label>
</template>

<script>
import { useField } from 'vee-validate';
import { toRef } from 'vue';
import {
    handleButtonComponentFocus,
    handleInputComponentBlur
} from '@/helpers/button-question-focus-helper';
import { inputButtonProps } from '@/digital-components/base-input-button/button-functionality-props';

export default {
    name: 'base-input-button',
    props: {
        ...inputButtonProps,
        buttonWrapperClasses: [String, Array, Object],
        inputClasses: [String, Array, Object]
    },
    emits: ['update:modelValue'],
    setup(props) {
        const inputType = props.isMultiSelect ? 'checkbox' : 'radio';

        const fieldOptions = {
            type: inputType,
            validateOnValueUpdate: false,
            validateOnMount: false,
            validateOnBlur: false
        };

        const { handleChange, meta, errors }
            = useField(toRef(props, 'groupName'),
                toRef(props, 'validationRules'),
                fieldOptions);

        return {
            handleChange,
            errors,
            meta,
            fieldOptions // only need to expose this for unit test purposes
        };
    },
    data() {
        return {
            valueToEmit: null
        };
    },
    computed: {
        isChecked() {
            if (this.isMultiSelect && this.modelValue instanceof Array) {
                return this.modelValue.includes(this.value);
            }
            if (!this.isMultiSelect) {
                return this.modelValue === this.value;
            }
            return false;
        },
        inputType() {
            return this.isMultiSelect ? 'checkbox' : 'radio';
        },
        buttonId() {
            return `${this.groupName}-${this.value}`.replaceAll(' ', '-');
        },
        isValueSelectedOnClick() {
            return this.isMultiSelect || this.selectingInitiatesLoad;
        },
        eventTypes() {
            return {
                CHANGE: 'change',
                ENTER: 'enter',
                SPACE: 'space',
                CLICK: 'click'
            };
        }
    },
    mounted() {
        if (this.isChecked) {
            this.handleChange(this.modelValue);
        }
    },
    methods: {
        handleEventAction(eventType, e) {
            if (this.isMultiSelect) {
                switch (eventType) {
                case this.eventTypes.CHANGE:
                    this.handleClick(e);
                    break;
                default:
                }
            } else {
                switch (eventType) {
                case this.eventTypes.CLICK:
                case this.eventTypes.ENTER:
                case this.eventTypes.SPACE:
                    this.handleClick(e);
                    break;
                case this.eventTypes.CHANGE:
                    // eslint-disable-next-line no-unused-expressions
                    this.selectingInitiatesLoad
                        ? this.handleSelectionChange(e)
                        : this.handleClick(e);
                    break;
                default:
                }
            }
        },
        handleSelectionChange() {
            if (
                this.isMultiSelect
                && (this.modelValue instanceof Array || this.modelValue == null)
            ) {
                const newValue = this.modelValue ? [...this.modelValue] : [];
                if (!newValue.includes(this.value)) {
                    newValue.push(this.value);
                } else {
                    newValue.splice(newValue.indexOf(this.value), 1);
                }

                this.valueToEmit = newValue;
            } else if (!this.isMultiSelect) {
                this.valueToEmit = this.value;
            }

            this.handleChange(this.valueToEmit);
        },
        handleClick(e) {
            this.handleSelectionChange(e);
            this.$emit('update:modelValue', this.valueToEmit);
        },
        handleFocus() {
            handleButtonComponentFocus({
                groupName: this.groupName
            });
        },
        handleBlur() {
            handleInputComponentBlur({
                groupName: this.groupName,
                onButtonQuestionLostFocusCallback: this.handlePushClickEventToGACheck
            });
        }
    }
};
</script>

<style lang="scss" scoped>
input {
    opacity: 0;
    height: 0.1px; // NOTE: cannot be zero or Safari can't put focus on it
    width: 0;
    position: absolute;
}
</style>
