<script setup lang="ts">

// types

type Props = {
    status?: "success" | "error" | "idle";
    modelValue: never[];
    autofocus?: boolean;
    disabled?: boolean;
}

// props

const props = withDefaults(defineProps<Props>(), {
    status: "idle"
});
const { modelValue, disabled, status } = toRefs(props);

// state

const { $gsap: gsap } = useNuxtApp();

// emit

const emit = defineEmits(["complete", "update:modelValue"]);

// state

const currentOtpCode = ref([]);

// methods

const handleChange = () => {
    emit("update:modelValue", currentOtpCode.value);
};

const handleComplete = () => {
    emit("update:modelValue", currentOtpCode.value);
    emit("complete", currentOtpCode.value);
};

const playStatusAnimation = () => {

    const inputCount = 6;
    const duration = 0.100;

    let statusColor = {
        border : "",
        bg : ""
    };

    if (status.value === "success") {
        statusColor.border = "var(--color-success-500)";
        statusColor.bg = "var(--color-success-50)";
    } else if (status.value === "error") {
        statusColor.border = "var(--color-danger-500)";
        statusColor.bg = "var(--color-danger-50)";
    }

    let index = 0;
    const animate = (index: number) => {
        setTimeout(() => {
            gsap.to(`#otp-input-${index}`, {
                borderColor: statusColor.border,
                backgroundColor: statusColor.bg,
                scale: 1.2,
                duration: duration / 2
            });

            gsap.to(`#otp-input-${index}`, {
                scale: 1,
                duration: duration / 2,
                delay: duration
            });

            setTimeout(() => {
                gsap.to(`#otp-input-${index}`, {
                    borderColor: "black",
                    backgroundColor: "var(--color-slate-50)"
                });
            }, (inputCount + 1) * duration * 3000);

        }, index * duration * 500);
    };

    while (index < 6) {
        animate(index);
        index++;
    }
};

// watch

watch(() => modelValue.value, (value) => {
    currentOtpCode.value = value;
});

watch(() => disabled.value, (value) => {
    if (!value) {
        const otpInputFirst = document.querySelector("#otp-input-0") as HTMLInputElement;
        setTimeout(() => {
            otpInputFirst.focus();
        }, 100);
    }
});

watch(() => status.value, (value) => {
    if (value !== "idle") {
        playStatusAnimation();
    }
});

</script>

<template>
    <div>
        <PinInputRoot
            :disabled="disabled"
            v-bind="$attrs"
            type="number"
            v-model="currentOtpCode"
            placeholder="_"
            class="flex gap-4 items-center justify-center mt-1"
            @change="handleChange"
            @complete="handleComplete"
            otp
        >
            <PinInputInput
                v-for="(id, index) in 6"
                :id="`otp-input-${index}`"
                :key="id"
                :index="index"
                :autofocus="autofocus ? index === 0 ? true : 'off' : 'off'"
                class="disabled:text-slate-400 focus-within:border-black transition-all size-16 bg-slate-50 typo-label-lg rounded-lg text-center border-[1.5px] border-slate-200 outline-none"
            />
        </PinInputRoot>
    </div>
</template>