/**
 * VariableProximity.js
 * Extracted and adapted from react-bits for Vanilla JavaScript interaction
 * Handles font-variation-settings interpolation based on mouse proximity.
 */

class VariableProximity {
  constructor(containerSelector, options = {}) {
    this.container = document.querySelector(containerSelector);
    if (!this.container) return;

    this.options = {
      fromSettings: { wght: 400, opsz: 14 },
      toSettings: { wght: 1000, opsz: 40 },
      radius: options.radius || 150,
      falloff: options.falloff || 'linear', // 'linear', 'exponential', 'gaussian'
      ...options
    };

    this.letters = this.container.querySelectorAll('.char');
    this.mouse = { x: 0, y: 0 };
    this.lastMouse = { x: -1, y: -1 };
    
    // Cache rects for performance
    this.containerRect = null;
    this.letterData = [];

    // Controle de pausa (economiza CPU quando hero fora da viewport)
    this.active = true;
    this._boundMouseMove = (e) => this.handleMouseMove(e);
    this._boundResize    = () => this.updateLayout();

    this.init();
  }

  init() {
    this.updateLayout();
    window.addEventListener('mousemove', this._boundMouseMove);
    window.addEventListener('resize',    this._boundResize);
    this.animate();
  }

  /** Pausa o rAF loop e remove o listener de mousemove */
  pause() {
    this.active = false;
    window.removeEventListener('mousemove', this._boundMouseMove);
  }

  /** Retoma o rAF loop e re-adiciona o listener de mousemove */
  resume() {
    if (this.active) return; // já ativo
    this.active = true;
    this.updateLayout(); // recalcula posições após scroll
    window.addEventListener('mousemove', this._boundMouseMove);
  }

  updateLayout() {
    this.containerRect = this.container.getBoundingClientRect();
    this.letterData = Array.from(this.letters).map(letter => {
      const rect = letter.getBoundingClientRect();
      return {
        el: letter,
        centerX: rect.left + rect.width / 2 - this.containerRect.left,
        centerY: rect.top + rect.height / 2 - this.containerRect.top
      };
    });
  }

  handleMouseMove(e) {
    this.mouse.x = e.clientX - this.containerRect.left;
    this.mouse.y = e.clientY - this.containerRect.top;
  }

  calculateDistance(x1, y1, x2, y2) {
    return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
  }

  calculateFalloff(distance) {
    const norm = Math.min(Math.max(1 - distance / this.options.radius, 0), 1);
    switch (this.options.falloff) {
      case 'exponential':
        return norm ** 2;
      case 'gaussian':
        return Math.exp(-((distance / (this.options.radius / 2)) ** 2) / 2);
      case 'linear':
      default:
        return norm;
    }
  }

  animate() {
    requestAnimationFrame(() => this.animate());

    // Para o processamento quando pausado ou mouse não moveu
    if (!this.active) return;
    if (this.mouse.x === this.lastMouse.x && this.mouse.y === this.lastMouse.y) return;
    this.lastMouse.x = this.mouse.x;
    this.lastMouse.y = this.mouse.y;

    this.letterData.forEach(data => {
      const distance = this.calculateDistance(this.mouse.x, this.mouse.y, data.centerX, data.centerY);

      if (distance >= this.options.radius) {
        data.el.style.fontVariationSettings = `'wght' ${this.options.fromSettings.wght}, 'opsz' ${this.options.fromSettings.opsz}`;
        return;
      }

      const falloffValue = this.calculateFalloff(distance);
      const wght = this.options.fromSettings.wght + (this.options.toSettings.wght - this.options.fromSettings.wght) * falloffValue;
      const opsz = this.options.fromSettings.opsz + (this.options.toSettings.opsz - this.options.fromSettings.opsz) * falloffValue;

      data.el.style.fontVariationSettings = `'wght' ${wght}, 'opsz' ${opsz}`;
    });
  }
}

// Export global for easy use
window.VariableProximity = VariableProximity;
