import { defineTrait } from '../define.js';
import { prefersReducedMotion } from '../motion.js';

export const countUp = defineTrait({
  name: 'count-up',
  category: 'audio-haptics-sensory',
  description: 'Animated numeric transitions',
  attributes: ['data-count-up-active'],
  events: ['count-up-done'],
  config: [
    'data-count-up-target',
    'data-count-duration',
    'data-count-prefix',
    'data-count-suffix',
    'data-count-decimals',
    'data-count-locale',
  ],
  setup({ host }) {
    const target   = parseFloat(host.getAttribute('data-count-up-target')) || 0;
    const duration = parseInt(host.getAttribute('data-count-duration'), 10) || 1000;
    const prefix   = host.getAttribute('data-count-prefix') ?? '';
    const suffix   = host.getAttribute('data-count-suffix') ?? '';
    const decimals = Math.max(0, parseInt(host.getAttribute('data-count-decimals'), 10) || 0);
    const locale   = host.getAttribute('data-count-locale') || undefined;

    // Locale-aware separators ("2,438,000" not "2438000"). The decimals attr
    // controls the fraction-digit count for currency / percentage cases
    // ($2,438,000.00 with decimals=2; 12.5% with decimals=1).
    const formatter = new Intl.NumberFormat(locale, {
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    });
    const fmt = (value) => `${prefix}${formatter.format(value)}${suffix}`;

    // Reduced-motion: jump straight to target and fire done event.
    if (prefersReducedMotion()) {
      host.textContent = fmt(target);
      host.setAttribute('data-count-up-active', '');
      queueMicrotask(() => {
        host.removeAttribute('data-count-up-active');
        host.dispatchEvent(new CustomEvent('count-up-done', { bubbles: true }));
      });
      return () => {
        host.removeAttribute('data-count-up-active');
      };
    }

    let rafId = null;

    function easeOutQuart(t) {
      return 1 - Math.pow(1 - t, 4);
    }

    const start = performance.now();
    host.setAttribute('data-count-up-active', '');

    function tick(now) {
      const elapsed = now - start;
      const progress = Math.min(elapsed / duration, 1);
      const value = target * easeOutQuart(progress);
      // Round to the configured decimal precision so the displayed value
      // doesn't flicker between fraction-bearing intermediates.
      const rounded = decimals > 0
        ? Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)
        : Math.round(value);
      host.textContent = fmt(rounded);

      if (progress < 1) {
        rafId = requestAnimationFrame(tick);
      } else {
        host.textContent = fmt(target);
        host.removeAttribute('data-count-up-active');
        host.dispatchEvent(new CustomEvent('count-up-done', { bubbles: true }));
      }
    }

    rafId = requestAnimationFrame(tick);

    return () => {
      if (rafId) cancelAnimationFrame(rafId);
      host.removeAttribute('data-count-up-active');
    };
  },
});
