<script setup lang="ts">
    import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
    import { storeToRefs } from 'pinia';
    import { buildYupChain, replaceValue } from '@/UI-kit/utils';
    import UIInput from '@/UI-kit/components/UI/inputs/UIInput.vue';
    import UIInfo from '@/UI-kit/components/UI/info/UIInfo.vue';
    import { EInputComponentType, EInputInputmode, UIColorName } from '@/UI-kit/types';
    import { useAuthStore, EAuthStep } from '@/modules/auth';
    import UIButton from '@/UI-kit/components/UI/button/UIButton.vue';
    import { useField, useForm } from 'vee-validate';
    import { string } from 'yup';
    import { requiredValueValidator } from '@/modules/documents/constants/validation/common.validation';
    import { UIColor } from '@/UI-kit/constants';
    import useRequestHandler from '@/UI-kit/composables/useRequestHandler';
    import type {
        IAuthCheckCodeFormProps,
        IAuthVerifyCodeResponse,
    } from '@/modules/auth/type/auth.type';

    const props = defineProps<IAuthCheckCodeFormProps>();

    const emit = defineEmits<{
        'email:confirmed': [void];
    }>();

    const authStore = useAuthStore();
    const { translates, authStep, userEmail } = storeToRefs(authStore);

    type InputElement = {
        focus: () => void;
        blur: () => void;
        setSelectionRange: (start: number, end: number) => void;
    };

    const inputs = ref<(InputElement | null)[]>([]);

    const errorResponseStatus = ref(false);
    const isFormSubmitted = ref(false);
    const isReady = ref(false);
    const activeInput = ref<number | null>(null);

    const formData = reactive({
        codeArray: ['', '', '', ''],
    });

    const {
        requestHandler: verifyCode,
        isLoading: isLoadingAuthEmailCodeVerificationUser,
        isError: isErrorAuthEmailCodeVerificationUser,
    } = useRequestHandler<{ code: string; email: string }, IAuthVerifyCodeResponse>({
        before: async () => {
            errorResponseStatus.value = false;
        },
        request: async (data: { code: string; email: string }) => {
            if (!props.apiMethods?.verifyCode) {
                throw new Error('API method verifyCode is not provided');
            }
            return await props.apiMethods.verifyCode(data);
        },
        then: async (response) => {
            if (response?.status === 'success') {
                authStep.value = EAuthStep.confirmed;
                emit('email:confirmed');
            } else {
                errorResponseStatus.value = true;
            }
        },
    });

    const { handleSubmit, errors, setFieldError } = useForm({
        validationSchema: {
            code: buildYupChain(string(), [requiredValueValidator()]).min(
                4,
                translates.value.input.error,
            ),
        },
    });

    const { value: code } = useField<string>('code');

    const hasInputCodeError = computed(() => {
        if (!isFormSubmitted.value) {
            return false;
        }
        return (
            isErrorAuthEmailCodeVerificationUser.value ||
            !!errors.value.code ||
            errorResponseStatus.value
        );
    });

    const resetErrorState = (key: any) => {
        setFieldError(key, '');
    };

    const update = (value: string, index: number) => {
        if (!isReady.value) {
            return;
        }

        errorResponseStatus.value = false;
        isFormSubmitted.value = false;
        resetErrorState('code');

        formData.codeArray[index] = value;

        if (value && index < inputs.value.length - 1) {
            inputs.value[index]?.blur();
            inputs.value[index + 1]?.focus();
            inputs.value[index + 1]?.setSelectionRange(0, 1);
            activeInput.value = index + 1;
        }

        if (!value && index > 0) {
            inputs.value[index - 1]?.focus();
            activeInput.value = index - 1;
        }

        code.value = formData.codeArray.join('') || '';
    };

    const send = async () => {
        isFormSubmitted.value = true;
        await handleSubmit(async () => {
            if (code.value && userEmail.value) {
                await verifyCode({ code: code.value, email: userEmail.value });
            }
        })();
    };

    const resetForm = () => {
        formData.codeArray = ['', '', '', ''];
        code.value = '';
        errorResponseStatus.value = false;
        isFormSubmitted.value = false;
        resetErrorState('code');
    };

    const resetFocus = (evt: Event) => {
        if (evt.target?.className === 'ui-input') {
            return;
        }
        activeInput.value = null;
    };

    onUnmounted(() => {
        resetForm();

        document.removeEventListener('click', resetFocus);
    });

    onMounted(() => {
        setTimeout(() => {
            isReady.value = true;
        }, 100);

        document.addEventListener('click', resetFocus);
    });

    watch(authStep, (newStep) => {
        if (newStep === EAuthStep.input) {
            resetForm();
        }
    });
</script>

<template>
    <div class="auth-check-code-form__inner">
        <div v-if="translates.input.description" v-html="translates.input.description" />
        <div v-html="replaceValue(translates.confirm.code.text, { email: userEmail })" />

        <div class="auth-check-code-form__inputs">
            <UIInput
                v-for="(_, index) in 4"
                :key="index"
                :ref="(el: any) => (inputs[index] = el)"
                v-model.trim="formData.codeArray[index]"
                mask="#"
                :component="EInputComponentType.mask"
                placeholder="0"
                class="auth-check-code-form__input"
                :class="{
                    '--error': hasInputCodeError,
                    '--active': activeInput === index,
                }"
                :inputmode="EInputInputmode.numeric"
                @update:model-value="update($event.trim(), index)"
                @input="resetErrorState('code')"
                @click="activeInput = index"
            />
        </div>
        <UIInfo
            v-if="hasInputCodeError"
            class="auth-check-code-form__error w-100"
            is-hide-icon
            is-hide-line
            :bg-color="UIColor.Red2"
            :color="UIColor[UIColorName.Red600]"
        >
            {{ translates.confirm.code.error }}
        </UIInfo>

        <UIButton
            :is-loading="isLoadingAuthEmailCodeVerificationUser"
            :disabled="isLoadingAuthEmailCodeVerificationUser"
            @click="send"
        >
            {{ translates.confirm.code.btn.ok }}
        </UIButton>
        <UIButton
            :bg-color="UIColor[UIColorName.Blue1]"
            :color="UIColor[UIColorName.Blue500]"
            :disabled="isLoadingAuthEmailCodeVerificationUser"
            @click="authStore.editSentEmail"
        >
            {{ translates.confirm.code.btn.cancel }}
        </UIButton>
    </div>
</template>

<style lang="scss" scoped>
    @use '@/UI-kit/assets/scss' as *;

    .auth-check-code-form {
        &__inner {
            @include text;
            @include flex(column);

            gap: 18px;
        }

        &__error {
            @include text(13px, 400, 20px, var(--red-600));
            @include flex(row, 0, center, center);

            margin: 4px 0 0;
            text-align: center;
        }

        &__inputs {
            @include flex(row, 0, center, center);

            gap: 10px;
            margin: 0 auto;
        }

        &__input {
            width: 60px;
            height: 60px;

            &:deep(.ui-input) {
                @include text(18px, 400, 24px);

                height: 60px;
                text-align: center;
                transition:
                    color 0.25s,
                    border 0.25s;

                &:hover,
                &:focus {
                    border-color: var(--gray-300);
                }

                &::placeholder {
                    font-size: 18px;
                }
            }

            &.--error {
                &:deep(.ui-input) {
                    color: var(--red-600);
                    border: 2px solid rgb(250 51 79 / 75%);
                    border-radius: 8px;
                }
            }

            &.--active {
                &:deep(.ui-input) {
                    border-color: var(--blue-500);
                }
            }
        }
    }
</style>
