/* ============================================================================
 * fingerprint.js — stable browser identifier for server-side playlist sync
 *
 * Combines canvas rendering, UA, screen geometry, and hardware hints into a
 * short hex string. The result is stored in localStorage so the same ID
 * survives page reloads, and only regenerated when localStorage is cleared.
 *
 * Not for tracking — used exclusively so the server can associate playlist
 * and history rows with this browser without requiring a login.
 * ========================================================================== */

(function () {
  'use strict';

  // djb2 hash over a string → 32-bit unsigned int
  function djb2(str) {
    let h = 5381;
    for (let i = 0; i < str.length; i++) {
      h = (((h << 5) + h) + str.charCodeAt(i)) >>> 0;
    }
    return h;
  }

  // Render a small canvas to capture GPU/font rasterisation differences,
  // then hash the pixel data. Falls back to empty string if canvas is blocked.
  function canvasHash() {
    try {
      const c = document.createElement('canvas');
      c.width = 200; c.height = 40;
      const ctx = c.getContext('2d');
      if (!ctx) return '';
      ctx.textBaseline = 'top';
      ctx.font = '14px Arial';
      ctx.fillStyle = '#f60';
      ctx.fillRect(125, 1, 62, 20);
      ctx.fillStyle = '#069';
      ctx.fillText('YTPlayer🎵', 2, 15);
      ctx.fillStyle = 'rgba(102,204,0,0.7)';
      ctx.fillText('YTPlayer🎵', 4, 17);
      return djb2(c.toDataURL()).toString(16);
    } catch {
      return '';
    }
  }

  function generateFingerprint() {
    const parts = [
      navigator.userAgent || '',
      String(screen.width) + 'x' + String(screen.height),
      String(screen.colorDepth),
      Intl.DateTimeFormat().resolvedOptions().timeZone || '',
      navigator.language || '',
      String(navigator.hardwareConcurrency || 0),
      String(navigator.deviceMemory || 0),
      canvasHash(),
    ];
    // Combine all component hashes into one 16-char hex fingerprint
    const combined = parts.reduce((acc, p) => acc + '|' + p, '');
    const h1 = djb2(combined);
    const h2 = djb2(combined.split('').reverse().join(''));
    return h1.toString(16).padStart(8, '0') + h2.toString(16).padStart(8, '0');
  }

  window.getFingerprint = function getFingerprint() {
    try {
      let fp = localStorage.getItem('_ytpfp');
      if (!fp || fp.length < 8) {
        fp = generateFingerprint();
        localStorage.setItem('_ytpfp', fp);
      }
      return fp;
    } catch {
      // localStorage blocked (e.g. private mode on some browsers) — generate
      // ephemeral fingerprint that survives the page session via a closure.
      if (!window._ytpfpEphemeral) {
        window._ytpfpEphemeral = generateFingerprint();
      }
      return window._ytpfpEphemeral;
    }
  };
}());
