<template>
    <span ref="spanEl">{{ display }}</span>
</template>

<script setup lang="ts">
/**
 * AnimatedCounter – zählt von 0 auf einen Zielwert hoch.
 * Verwendet requestAnimationFrame mit Ease-out-Cubic.
 *
 * Props:
 *   target   – Zielwert (required)
 *   duration – Animationsdauer in ms (default 1800)
 *   delay    – Startverzögerung in ms (default 0)
 *   decimals – Nachkommastellen (default 0)
 */
const props = withDefaults(defineProps<{
    target: number;
    duration?: number;
    delay?: number;
    decimals?: number;
}>(), {
    duration: 1800,
    delay: 0,
    decimals: 0,
});

const display = ref(props.decimals > 0 ? (0).toFixed(props.decimals) : '0');
const spanEl = ref<HTMLElement | null>(null);
let started = false;

function runAnimation() {
    const startTime = performance.now();
    const update = (now: number) => {
        const elapsed = now - startTime;
        const progress = Math.min(elapsed / props.duration, 1);
        const eased = 1 - Math.pow(1 - progress, 3); // ease-out cubic
        const current = eased * props.target;
        display.value = props.decimals > 0
            ? current.toFixed(props.decimals)
            : Math.round(current).toString();
        if (progress < 1) requestAnimationFrame(update);
    };
    requestAnimationFrame(update);
}

onMounted(() => {
    const observer = new IntersectionObserver(([entry]) => {
        if (entry.isIntersecting && !started) {
            started = true;
            observer.disconnect();
            setTimeout(runAnimation, props.delay);
        }
    }, { threshold: 0.3 });
    if (spanEl.value) observer.observe(spanEl.value);
    onUnmounted(() => observer.disconnect());
});
</script>
