/* ═══════════════════════════════════════════════════════════════
   PIXEL CARD — Vanilla JS Port
   Original: @react-bits/PixelCard (React)
   ─────────────────────────────────────────────────────────────
   Auto-initialises every element with class .pixel-card that
   also has .pc-dynamic (triggers the pixel effect on hover).

   Usage:
     <div class="pixel-card pixel-card--pink pc-dynamic">
       <canvas class="pixel-canvas"></canvas>
       <div style="position: absolute;">Content</div>
     </div>
   ═══════════════════════════════════════════════════════════════ */

(function () {
  'use strict';

  /* ── Variant configurations ── */
  const VARIANTS = {
    default: { activeColor: null,      gap: 5,  speed: 35, colors: '#f8fafc,#f1f5f9,#cbd5e1', noFocus: false },
    blue:    { activeColor: '#e0f2fe', gap: 10, speed: 25, colors: '#e0f2fe,#7dd3fc,#0ea5e9', noFocus: false },
    yellow:  { activeColor: '#fef08a', gap: 3,  speed: 20, colors: '#fef08a,#fde047,#eab308', noFocus: false },
    pink:    { activeColor: '#fecdd3', gap: 6,  speed: 80, colors: '#fecdd3,#fda4af,#e11d48', noFocus: true  },
    purple:  { activeColor: '#d8b4fe', gap: 6,  speed: 50, colors: '#c4b5fd,#a78bfa,#7B2FFF', noFocus: false },
    cyan:    { activeColor: '#a5f3fc', gap: 5,  speed: 40, colors: '#cffafe,#67e8f9,#00D4FF', noFocus: false, maxSize: 2 },
    white:   { activeColor: '#f8fafc', gap: 4,  speed: 45, colors: '#7B2FFF,#E040FB,#00D4FF,#27272a', noFocus: false, maxSize: 2.5 },
    primary: { activeColor: '#e9d5ff', gap: 5,  speed: 50, colors: '#c4b5fd,#E040FB,#7B2FFF', noFocus: false, maxSize: 2 },
    secondary:{activeColor: '#f3f4f6', gap: 5,  speed: 35, colors: '#e5e7eb,#9ca3af,#6b7280', noFocus: false, maxSize: 2 },
    success: { activeColor: '#d1fae5', gap: 5,  speed: 40, colors: '#a7f3d0,#34d399,#10b981', noFocus: false, maxSize: 2 },
    danger:  { activeColor: '#fee2e2', gap: 6,  speed: 45, colors: '#fecaca,#f87171,#ef4444', noFocus: false, maxSize: 2 },
    warning: { activeColor: '#fef3c7', gap: 4,  speed: 30, colors: '#fde68a,#fbbf24,#f59e0b', noFocus: false, maxSize: 2 },
    info:    { activeColor: '#e0f2fe', gap: 5,  speed: 40, colors: '#bae6fd,#38bdf8,#0ea5e9', noFocus: false, maxSize: 2 },

    /* White Semantic Variants */
    'white-primary': { activeColor: '#f8fafc', gap: 4, speed: 60, colors: '#E040FB,#7B2FFF,#27272a', noFocus: false, maxSize: 2.5 },
    'white-secondary':{activeColor: '#f8fafc', gap: 4, speed: 60, colors: '#9ca3af,#6b7280,#27272a', noFocus: false, maxSize: 2.5 },
    'white-success': { activeColor: '#f8fafc', gap: 4, speed: 60, colors: '#34d399,#10b981,#27272a', noFocus: false, maxSize: 2.5 },
    'white-danger':  { activeColor: '#f8fafc', gap: 4, speed: 60, colors: '#f87171,#ef4444,#27272a', noFocus: false, maxSize: 2.5 },
    'white-warning': { activeColor: '#f8fafc', gap: 4, speed: 60, colors: '#fbbf24,#f59e0b,#27272a', noFocus: false, maxSize: 2.5 },
    'white-info':    { activeColor: '#f8fafc', gap: 4, speed: 60, colors: '#38bdf8,#0ea5e9,#27272a', noFocus: false, maxSize: 2.5 },
  };

  /* ── Pixel Class ── */
  class Pixel {
    constructor(canvas, context, x, y, color, speed, delay, maxSize = 2) {
      this.width = canvas.width;
      this.height = canvas.height;
      this.ctx = context;
      this.x = x;
      this.y = y;
      this.color = color;
      this.speed = this.rand(0.1, 0.9) * speed;
      this.size = 0;
      this.sizeStep = Math.random() * 0.4;
      this.minSize = 0.5;
      this.maxSizeInteger = maxSize;
      this.maxSize = this.rand(this.minSize, this.maxSizeInteger);
      this.delay = delay;
      this.counter = 0;
      this.counterStep = Math.random() * 4 + (this.width + this.height) * 0.01;
      this.isIdle = false;
      this.isReverse = false;
      this.isShimmer = false;
    }

    rand(min, max) { return Math.random() * (max - min) + min; }

    draw() {
      const offset = this.maxSizeInteger * 0.5 - this.size * 0.5;
      this.ctx.fillStyle = this.color;
      this.ctx.fillRect(this.x + offset, this.y + offset, this.size, this.size);
    }

    appear() {
      this.isIdle = false;
      if (this.counter <= this.delay) { this.counter += this.counterStep; return; }
      if (this.size >= this.maxSize) this.isShimmer = true;
      if (this.isShimmer) this.shimmer(); else this.size += this.sizeStep;
      this.draw();
    }

    disappear() {
      this.isShimmer = false;
      this.counter = 0;
      if (this.size <= 0) { this.isIdle = true; return; }
      this.size -= 0.1;
      this.draw();
    }

    shimmer() {
      if (this.size >= this.maxSize) this.isReverse = true;
      else if (this.size <= this.minSize) this.isReverse = false;
      if (this.isReverse) this.size -= this.speed; else this.size += this.speed;
    }
  }

  /* ── Speed helper ── */
  function getEffectiveSpeed(value, reducedMotion) {
    const parsed = parseInt(value, 10);
    if (parsed <= 0 || reducedMotion) return 0;
    if (parsed >= 100) return 0.1;
    return parsed * 0.001;
  }

  /* ── Init a single .pixel-card.pc-dynamic element ── */
  function initPixelCard(el) {
    if (el._pcInit) return;
    el._pcInit = true;

    /* Find or create canvas */
    let canvas = el.querySelector('.pixel-canvas');
    if (!canvas) {
      canvas = document.createElement('canvas');
      canvas.className = 'pixel-canvas';
      el.insertBefore(canvas, el.firstChild);
    }

    const ctx = canvas.getContext('2d');
    const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    /* Detect variant from class list */
    let variantKey = 'default';
    Object.keys(VARIANTS).forEach(k => {
      if (el.classList.contains(`pixel-card--${k}`) || el.classList.contains(`pixel-btn--${k}`)) variantKey = k;
    });
    const cfg = VARIANTS[variantKey];

    /* Read data-* overrides */
    const gap    = parseInt(el.dataset.pcGap    ?? cfg.gap,   10);
    const speed  = parseInt(el.dataset.pcSpeed  ?? cfg.speed, 10);
    const colors = (el.dataset.pcColors ?? cfg.colors).split(',');
    const noFocus = el.dataset.pcNofocus != null ? true : cfg.noFocus;

    let pixels = [];
    let animId = null;
    let lastTime = performance.now();

    /* ── Build pixel grid ── */
    function initPixels() {
      const rect = el.getBoundingClientRect();
      const w = Math.floor(rect.width);
      const h = Math.floor(rect.height);

      canvas.width  = w;
      canvas.height = h;

      pixels = [];
      for (let x = 0; x < w; x += gap) {
        for (let y = 0; y < h; y += gap) {
          const color    = colors[Math.floor(Math.random() * colors.length)];
          const dx       = x - w / 2;
          const dy       = y - h / 2;
          const distance = Math.sqrt(dx * dx + dy * dy);
          const delay    = reducedMotion ? 0 : distance;
          pixels.push(new Pixel(canvas, ctx, x, y, color, getEffectiveSpeed(speed, reducedMotion), delay, cfg.maxSize || 2));
        }
      }
    }

    /* ── Animation loop ── */
    function doAnimate(fnName) {
      animId = requestAnimationFrame(() => doAnimate(fnName));
      const now     = performance.now();
      const elapsed = now - lastTime;
      if (elapsed < 1000 / 60) return;
      lastTime = now - (elapsed % (1000 / 60));

      ctx.clearRect(0, 0, canvas.width, canvas.height);
      let allIdle = true;
      for (const p of pixels) {
        p[fnName]();
        if (!p.isIdle) allIdle = false;
      }
      if (allIdle) cancelAnimationFrame(animId);
    }

    function handleAnimation(fnName) {
      cancelAnimationFrame(animId);
      animId = requestAnimationFrame(() => doAnimate(fnName));
    }

    /* ── Event listeners ── */
    el.addEventListener('mouseenter', () => handleAnimation('appear'));
    el.addEventListener('mouseleave', () => handleAnimation('disappear'));

    if (!noFocus) {
      el.setAttribute('tabindex', el.getAttribute('tabindex') ?? '0');
      el.addEventListener('focus', e => { if (!el.contains(e.relatedTarget)) handleAnimation('appear');    }, true);
      el.addEventListener('blur',  e => { if (!el.contains(e.relatedTarget)) handleAnimation('disappear'); }, true);
    }

    /* ── Resize observer ── */
    const ro = new ResizeObserver(() => initPixels());
    ro.observe(el);

    /* ── Initial build ── */
    initPixels();
  }

  /* ── Auto-init all .pixel-card.pc-dynamic ── */
  function initAll() {
    document.querySelectorAll('.pixel-card.pc-dynamic').forEach(initPixelCard);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initAll);
  } else {
    initAll();
  }

  /* ── Public API ── */
  window.PixelCard = { init: initPixelCard, initAll };
})();
