// ── Color utils ─────────────────────────────────────────────────
function hexToRgb(hex) {
  const h = (hex || '').replace('#', '');
  const v = h.length === 3 ? h.split('').map(c => c + c).join('') : h;
  return {
    r: parseInt(v.slice(0, 2), 16) || 0,
    g: parseInt(v.slice(2, 4), 16) || 0,
    b: parseInt(v.slice(4, 6), 16) || 0,
  };
}
function rgba(hex, a) {
  const {r, g, b} = hexToRgb(hex);
  return `rgba(${r},${g},${b},${a})`;
}
function shade(hex, pct) {
  const {r, g, b} = hexToRgb(hex);
  const k = pct < 0 ? 0 : 255;
  const t = Math.abs(pct);
  const ch = (c) => Math.round((k - c) * t + c);
  const toHex = (x) => x.toString(16).padStart(2, '0');
  return `#${toHex(ch(r))}${toHex(ch(g))}${toHex(ch(b))}`;
}
function contrastText(hex) {
  const {r, g, b} = hexToRgb(hex);
  // Relative luminance per WCAG
  const lum = 0.2126 * (r/255) + 0.7152 * (g/255) + 0.0722 * (b/255);
  return lum > 0.55 ? '#111111' : '#FFFFFF';
}
window.hexToRgb = hexToRgb;
window.rgba = rgba;
window.shade = shade;
window.contrastText = contrastText;

// ── QRCode ──────────────────────────────────────────────────────
function QRCode({ value, size = 200, fg = '#000', bg = '#FFF' }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!ref.current) return;
    try {
      const qr = qrcode(0, 'M');
      qr.addData(value || 'https://flip.com');
      qr.make();
      // Build SVG manually so we can control colors
      const cells = qr.getModuleCount();
      const cellSize = size / cells;
      let path = '';
      for (let r = 0; r < cells; r++) {
        for (let c = 0; c < cells; c++) {
          if (qr.isDark(r, c)) {
            path += `M${c * cellSize},${r * cellSize}h${cellSize}v${cellSize}h-${cellSize}z`;
          }
        }
      }
      ref.current.innerHTML =
        `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
           <rect width="${size}" height="${size}" fill="${bg}"/>
           <path d="${path}" fill="${fg}"/>
         </svg>`;
    } catch (e) {
      ref.current.innerHTML = '';
    }
  }, [value, size, fg, bg]);
  return <div ref={ref} style={{width: size, height: size, lineHeight: 0}}/>;
}
window.QRCode = QRCode;

// ── ClientMark — logo if uploaded, else initials in a tile ──────
function ClientMark({ logoUrl, name, color = '#FFFFFF', size = 80, shape = 'tile' }) {
  const inner = logoUrl
    ? <img src={logoUrl} alt={name}
           style={{width: '100%', height: '100%', objectFit: 'contain'}}/>
    : <div style={{
        width: '100%', height: '100%',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color, fontWeight: 600, fontSize: size * 0.42,
        letterSpacing: '-0.02em',
      }}>{(name || '?').slice(0, 2).toUpperCase()}</div>;
  return (
    <div style={{
      width: size, height: size,
      borderRadius: shape === 'circle' ? '50%' : size * 0.18,
      overflow: 'hidden',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>{inner}</div>
  );
}
window.ClientMark = ClientMark;

// ── FlipWordmark — official Flip logo (swirl + flip) ────────────
function FlipWordmark({ height = 22, color = '#2151F5' }) {
  const aspect = 2190 / 919;
  return (
    <svg height={height} width={height * aspect} viewBox="0 0 2190 919"
         xmlns="http://www.w3.org/2000/svg" fill={color}
         style={{display: 'block'}}>
      <path d="M1976.88 264.044C1925.22 261.155 1875.3 282.882 1842.36 322.754V275.139H1790.7C1744.59 275.139 1707.14 312.584 1707.14 358.697V918.52H1763.66C1809.77 918.52 1847.21 881.076 1847.21 834.963V704.021C1879.34 736.844 1924.18 754.063 1970.06 751.29C2098.35 751.29 2190 649.357 2190 507.089C2190 364.822 2109.56 264.044 1976.88 264.044ZM1959.55 622.544C1902.34 628.438 1851.14 586.833 1845.25 529.625C1844.55 522.46 1844.55 515.41 1845.25 508.245C1839.35 451.038 1880.96 399.84 1938.17 393.946C1995.37 388.052 2046.57 429.657 2052.47 486.864C2053.16 494.03 2053.16 501.08 2052.47 508.245C2058.24 565.452 2016.75 616.65 1959.55 622.544Z"/>
      <path d="M1471.72 359.74V740.66H1528.23C1574.35 740.66 1611.79 703.215 1611.79 657.103V275.836H1555.74C1509.39 276.067 1471.95 313.512 1471.72 359.74Z"/>
      <path d="M1236.88 161.426V748.062L1293.4 747.716C1339.51 747.716 1376.95 710.271 1376.95 664.158V77.522H1320.44C1274.21 77.6376 1236.88 115.198 1236.88 161.426Z"/>
      <path d="M750.218 231.806V747.713H813.32C859.548 747.713 896.877 710.269 896.877 664.156V491.378H993.111C1039.34 491.378 1076.9 454.049 1077.13 407.82V356.854H895.837V266.709C895.837 238.972 918.373 216.435 946.11 216.435H1088.03C1134.26 216.435 1171.59 178.991 1171.59 132.878V76.0172H906.007C820.023 76.0172 750.218 145.822 750.218 231.806Z"/>
      <path d="M1542.9 76.0174C1504.64 75.9202 1473.46 106.826 1473.37 145.117C1473.27 183.409 1504.15 214.606 1542.42 214.703C1560.87 214.703 1578.64 207.414 1591.75 194.391C1604.67 181.465 1611.95 163.874 1612.05 145.603C1612.05 107.312 1581.17 76.2118 1542.9 76.0174Z"/>
      <path d="M50.1255 544.446C42.9788 550.235 32.4014 549.042 27.4556 541.288C18.5609 527.343 11.4434 512.075 6.57378 495.864C0.952296 472.94 -1.33402 450.596 0.773351 428.671C2.88072 406.747 10.2366 384.031 20.392 365.224C31.4023 345.205 45.0458 327.992 63.5244 314.425L447.214 3.63045C454.36 -2.15845 464.938 -0.965651 469.883 6.78836C478.778 20.7335 485.896 36.0014 490.765 52.212C497.286 73.9181 498.513 96.4221 496.566 119.405C494.458 141.329 487.102 164.045 476.947 182.852C465.937 202.871 452.293 220.085 433.815 233.651L50.1255 544.446Z"/>
      <path d="M198.64 791.136C191.494 796.927 180.915 795.735 175.969 787.98C167.075 774.035 159.957 758.768 155.088 742.558C148.568 720.852 147.34 698.348 149.288 675.365C151.395 653.441 158.751 630.725 168.906 611.918C179.917 591.899 193.56 574.686 212.039 561.119L418.566 393.778C425.712 387.987 436.291 389.179 441.237 396.934C450.131 410.879 457.248 426.146 462.118 442.356C468.638 464.062 469.866 486.566 467.918 509.549C465.811 531.473 458.455 554.189 448.299 572.996C437.289 593.015 423.646 610.228 405.167 623.795L198.64 791.136Z"/>
    </svg>
  );
}
window.FlipWordmark = FlipWordmark;

// ── FlipSwirl — JUST the f-swirl mark (no wordmark). Use as the
// app-icon glyph inside a card / button / lockup.
//
// Paths are the canonical Flip swirl, lifted from the wordmark in
// assets/logo/flip-wordmark.svg (the two left-most strokes on a
// 500×800 viewBox). The swirl is taller than wide (aspect ~0.625);
// `size` is the WIDTH and the height is computed.
function FlipSwirl({ size = 100, color = '#2151F5' }) {
  return (
    <svg width={size} height={size * (800 / 500)} viewBox="0 0 500 800"
         xmlns="http://www.w3.org/2000/svg" fill={color}
         style={{display: 'block'}}>
      <path d="M50.1255 544.446C42.9788 550.235 32.4014 549.042 27.4556 541.288C18.5609 527.343 11.4434 512.075 6.57378 495.864C0.952296 472.94 -1.33402 450.596 0.773351 428.671C2.88072 406.747 10.2366 384.031 20.392 365.224C31.4023 345.205 45.0458 327.992 63.5244 314.425L447.214 3.63045C454.36 -2.15845 464.938 -0.965651 469.883 6.78836C478.778 20.7335 485.896 36.0014 490.765 52.212C497.286 73.9181 498.513 96.4221 496.566 119.405C494.458 141.329 487.102 164.045 476.947 182.852C465.937 202.871 452.293 220.085 433.815 233.651L50.1255 544.446Z"/>
      <path d="M198.64 791.136C191.494 796.927 180.915 795.735 175.969 787.98C167.075 774.035 159.957 758.768 155.088 742.558C148.568 720.852 147.34 698.348 149.288 675.365C151.395 653.441 158.751 630.725 168.906 611.918C179.917 591.899 193.56 574.686 212.039 561.119L418.566 393.778C425.712 387.987 436.291 389.179 441.237 396.934C450.131 410.879 457.248 426.146 462.118 442.356C468.638 464.062 469.866 486.566 467.918 509.549C465.811 531.473 458.455 554.189 448.299 572.996C437.289 593.015 423.646 610.228 405.167 623.795L198.64 791.136Z"/>
    </svg>
  );
}
window.FlipSwirl = FlipSwirl;

// ── PhoneMock — generic phone frame with optional screenshot ────
// `tilt` rotates the device for editorial layouts; `screenImg` is a
// data URL or path to the screen content. If absent, renders a faux
// brand-tinted screen with a small Flip swirl glow.
function PhoneMock({ width, height, tilt = 0, screenImg, accent = '#2151F5' }) {
  const r = Math.min(width, height) * 0.10;       // device corner radius
  const sr = r * 0.85;                              // screen corner radius
  const bezel = Math.min(width, height) * 0.025;
  const sw = width  - bezel * 2;
  const sh = height - bezel * 2;
  const id = React.useMemo(() => Math.random().toString(36).slice(2, 9), []);
  const glowA = rgba(accent, 0.55);
  const glowB = rgba(shade(accent, 0.4), 0.65);

  return (
    <div style={{
      width, height, position: 'relative',
      transform: tilt ? `rotate(${tilt}deg)` : undefined,
      transformOrigin: 'center',
    }}>
      {/* drop shadow underneath */}
      <div style={{
        position: 'absolute', inset: 0, borderRadius: r,
        boxShadow: '0 22px 50px rgba(0,0,0,0.35), 0 8px 18px rgba(0,0,0,0.25)',
      }}/>
      {/* device body */}
      <div style={{
        position: 'absolute', inset: 0, borderRadius: r,
        background: 'linear-gradient(180deg, #1a1a1c 0%, #0d0d0e 100%)',
        border: '1px solid rgba(255,255,255,0.08)',
      }}/>
      {/* screen */}
      <div style={{
        position: 'absolute', left: bezel, top: bezel,
        width: sw, height: sh, borderRadius: sr,
        overflow: 'hidden',
        background: '#FFFFFF',
      }}>
        {screenImg ? (
          <img src={screenImg} alt=""
               style={{width: '100%', height: '100%', objectFit: 'cover'}}/>
        ) : (
          <div style={{
            position: 'relative', width: '100%', height: '100%',
            background: '#FFFFFF',
          }}>
            {/* feathered diamond glow as a subtle backdrop */}
            <svg viewBox="0 0 100 205" preserveAspectRatio="none"
                 style={{position: 'absolute', inset: 0, width: '100%', height: '100%',
                         filter: 'blur(22px)', opacity: 0.7}}>
              <defs>
                <radialGradient id={`g-tl-${id}`} cx="20%" cy="15%" r="70%">
                  <stop offset="0%"   stopColor={glowA} stopOpacity="0.9"/>
                  <stop offset="45%"  stopColor={glowA} stopOpacity="0.3"/>
                  <stop offset="100%" stopColor={glowA} stopOpacity="0"/>
                </radialGradient>
                <radialGradient id={`g-br-${id}`} cx="85%" cy="85%" r="70%">
                  <stop offset="0%"   stopColor={glowB} stopOpacity="0.9"/>
                  <stop offset="45%"  stopColor={glowB} stopOpacity="0.3"/>
                  <stop offset="100%" stopColor={glowB} stopOpacity="0"/>
                </radialGradient>
              </defs>
              <rect width="100" height="205" fill={`url(#g-tl-${id})`}/>
              <rect width="100" height="205" fill={`url(#g-br-${id})`}/>
            </svg>
            {/* faux app shell */}
            <div style={{
              position: 'absolute', top: '8%', left: '8%', right: '8%', height: '5%',
              borderRadius: 4, background: 'rgba(0,0,0,0.06)',
            }}/>
            <div style={{
              position: 'absolute', top: '18%', left: '8%', right: '8%', height: '38%',
              borderRadius: 12, background: 'rgba(33,81,245,0.10)',
              border: '1px solid rgba(33,81,245,0.18)',
            }}/>
            <div style={{
              position: 'absolute', top: '60%', left: '8%', right: '52%', height: '8%',
              borderRadius: 6, background: 'rgba(0,0,0,0.10)',
            }}/>
            <div style={{
              position: 'absolute', top: '60%', left: '52%', right: '8%', height: '8%',
              borderRadius: 6, background: 'rgba(0,0,0,0.06)',
            }}/>
            <div style={{
              position: 'absolute', top: '72%', left: '8%', right: '8%', height: '4%',
              borderRadius: 4, background: 'rgba(0,0,0,0.06)',
            }}/>
            <div style={{
              position: 'absolute', top: '78%', left: '8%', right: '32%', height: '4%',
              borderRadius: 4, background: 'rgba(0,0,0,0.06)',
            }}/>
          </div>
        )}
      </div>
    </div>
  );
}
window.PhoneMock = PhoneMock;
