/* ═══════════════════════════════════════════════════════════════
   glass-surface.js — Vanilla JS port of @react-bits/GlassSurface
   ─────────────────────────────────────────────────────────────
   Auto-initialises every element with class .glass-surface that
   also has .gs-dynamic (the full SVG displacement effect).
   Elements without .gs-dynamic use the pure-CSS fallback only.
   ═══════════════════════════════════════════════════════════════ */

(function () {
  'use strict';

  /* ── Browser support check ──────────────────────────────── */
  function supportsSVGBackdrop () {
    if (typeof window === 'undefined') return false;
    const ua = navigator.userAgent;
    const isWebkit  = /Safari/.test(ua) && !/Chrome/.test(ua);
    const isFirefox = /Firefox/.test(ua);
    if (isWebkit || isFirefox) return false;
    const d = document.createElement('div');
    d.style.backdropFilter = 'url(#test)';
    return d.style.backdropFilter !== '';
  }

  const SVG_SUPPORTED = supportsSVGBackdrop();

  /* ── Unique ID helper ───────────────────────────────────── */
  let gsCounter = 0;
  function uid () { return `gs-${++gsCounter}`; }

  /* ── Build displacement-map SVG data URL ─────────────────── */
  function buildDisplacementMap (opts) {
    const {
      w, h,
      borderRadius  = 20,
      borderWidth   = 0.07,
      brightness    = 50,
      opacity       = 0.93,
      blur          = 11,
      mixBlendMode  = 'difference',
      redGradId, blueGradId
    } = opts;

    const edgeSize = Math.max(w, h) * (borderWidth * 0.4);
    const innerRadius = Math.max(0, borderRadius - edgeSize * 0.5);

    const svg = `<svg viewBox="0 0 ${w} ${h}" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <linearGradient id="${redGradId}" x1="100%" y1="0%" x2="0%" y2="0%">
          <stop offset="0%" stop-color="#0000"/>
          <stop offset="100%" stop-color="red"/>
        </linearGradient>
        <linearGradient id="${blueGradId}" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" stop-color="#0000"/>
          <stop offset="100%" stop-color="blue"/>
        </linearGradient>
      </defs>
      <rect x="0" y="0" width="${w}" height="${h}" rx="${borderRadius}" fill="black"/>
      <rect x="0" y="0" width="${w}" height="${h}" rx="${borderRadius}" fill="url(#${redGradId})"/>
      <rect x="0" y="0" width="${w}" height="${h}" rx="${borderRadius}" fill="url(#${blueGradId})" style="mix-blend-mode:${mixBlendMode}"/>
      <rect x="${edgeSize}" y="${edgeSize}"
            width="${Math.max(1, w - edgeSize * 2)}" height="${Math.max(1, h - edgeSize * 2)}"
            rx="${innerRadius}"
            fill="hsl(0 0% ${brightness}% / ${opacity})"
            style="filter:blur(${blur}px)"/>
    </svg>`;

    return `data:image/svg+xml,${encodeURIComponent(svg)}`;
  }

  /* ── Initialise a single .glass-surface.gs-dynamic element ── */
  function initGlassSurface (el) {
    /* Skip if already initialised */
    if (el._gsInit) return;
    el._gsInit = true;

    const id         = uid();
    const filterId   = `gs-filter-${id}`;
    const redGradId  = `gs-red-${id}`;
    const blueGradId = `gs-blue-${id}`;

    /* ── Read data-* config (all optional) ── */
    const cfg = {
      borderRadius   : parseFloat(el.dataset.gsRadius   ?? 20),
      borderWidth    : parseFloat(el.dataset.gsBorder   ?? 0.07),
      brightness     : parseFloat(el.dataset.gsBright   ?? 50),
      opacity        : parseFloat(el.dataset.gsOpacity  ?? 0.93),
      blur           : parseFloat(el.dataset.gsBlur     ?? 11),
      displace       : parseFloat(el.dataset.gsDisplace ?? 0),
      distortionScale: parseFloat(el.dataset.gsDistort  ?? -180),
      redOffset      : parseFloat(el.dataset.gsRed      ?? 0),
      greenOffset    : parseFloat(el.dataset.gsGreen    ?? 10),
      blueOffset     : parseFloat(el.dataset.gsBlue     ?? 20),
      xChannel       : el.dataset.gsXchan ?? 'R',
      yChannel       : el.dataset.gsYchan ?? 'G',
      mixBlendMode   : el.dataset.gsMix   ?? 'difference',
    };

    /* ── Inject SVG filter into element ── */
    const svgNS = 'http://www.w3.org/2000/svg';
    const svg   = document.createElementNS(svgNS, 'svg');
    svg.classList.add('glass-surface__filter');
    svg.setAttribute('xmlns', svgNS);

    svg.innerHTML = `
      <defs>
        <filter id="${filterId}" color-interpolation-filters="sRGB" x="0%" y="0%" width="100%" height="100%">
          <feImage id="${filterId}-img" x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="map"/>
          <feDisplacementMap id="${filterId}-red"   in="SourceGraphic" in2="map" result="dispRed"/>
          <feColorMatrix in="dispRed" type="matrix"
            values="1 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 1 0" result="red"/>
          <feDisplacementMap id="${filterId}-green" in="SourceGraphic" in2="map" result="dispGreen"/>
          <feColorMatrix in="dispGreen" type="matrix"
            values="0 0 0 0 0  0 1 0 0 0  0 0 0 0 0  0 0 0 1 0" result="green"/>
          <feDisplacementMap id="${filterId}-blue"  in="SourceGraphic" in2="map" result="dispBlue"/>
          <feColorMatrix in="dispBlue" type="matrix"
            values="0 0 0 0 0  0 0 0 0 0  0 0 1 0 0  0 0 0 1 0" result="blue"/>
          <feBlend in="red" in2="green" mode="screen" result="rg"/>
          <feBlend in="rg"  in2="blue"  mode="screen" result="output"/>
          <feGaussianBlur id="${filterId}-blur" in="output" stdDeviation="0.7"/>
        </filter>
      </defs>`;

    el.insertBefore(svg, el.firstChild);

    /* ── Apply backdrop-filter if supported ── */
    if (SVG_SUPPORTED) {
      el.style.setProperty('--gs-filter-id', `url(#${filterId})`);
      el.style.backdropFilter = `url(#${filterId}) saturate(1)`;
    }

    /* ── Cache feImage & feDisplacementMap refs ── */
    const feImg   = svg.querySelector(`#${filterId}-img`);
    const feRed   = svg.querySelector(`#${filterId}-red`);
    const feGreen = svg.querySelector(`#${filterId}-green`);
    const feBlue  = svg.querySelector(`#${filterId}-blue`);
    const feBlur  = svg.querySelector(`#${filterId}-blur`);

    /* ── Update displacement map ── */
    function update () {
      const rect = el.getBoundingClientRect();
      const w    = rect.width  || 200;
      const h    = rect.height || 80;

      const href = buildDisplacementMap({
        w, h,
        borderRadius : cfg.borderRadius,
        borderWidth  : cfg.borderWidth,
        brightness   : cfg.brightness,
        opacity      : cfg.opacity,
        blur         : cfg.blur,
        mixBlendMode : cfg.mixBlendMode,
        redGradId, blueGradId,
      });

      feImg.setAttribute('href', href);

      [
        { el: feRed,   offset: cfg.redOffset   },
        { el: feGreen, offset: cfg.greenOffset  },
        { el: feBlue,  offset: cfg.blueOffset   },
      ].forEach(({ el: fe, offset }) => {
        fe.setAttribute('scale',            String(cfg.distortionScale + offset));
        fe.setAttribute('xChannelSelector', cfg.xChannel);
        fe.setAttribute('yChannelSelector', cfg.yChannel);
      });

      feBlur.setAttribute('stdDeviation', String(cfg.displace));
    }

    /* ── Initial render + ResizeObserver ── */
    setTimeout(update, 0);

    const ro = new ResizeObserver(() => setTimeout(update, 0));
    ro.observe(el);
  }

  /* ── Auto-init all .glass-surface.gs-dynamic ─────────────── */
  function initAll () {
    document.querySelectorAll('.glass-surface.gs-dynamic').forEach(initGlassSurface);
  }

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

  /* ── Public API ── */
  window.GlassSurface = { init: initGlassSurface, initAll };

})();
