// shared.jsx — Greek/marble UI kit for greekslaves.beer
// Primitives, decorations, sounds, confetti. All component names prefixed Gs.

// ─── Color tokens ────────────────────────────────────────────
const GREEK = {
  marble: 'oklch(0.97 0.005 80)',       // off-white marble
  parchment: 'oklch(0.92 0.02 80)',     // aged paper
  parchmentDeep: 'oklch(0.84 0.04 80)', // deeper edges
  wine: 'oklch(0.38 0.12 25)',          // burgundy
  wineDeep: 'oklch(0.28 0.10 25)',
  gold: 'oklch(0.78 0.13 80)',
  goldDeep: 'oklch(0.62 0.14 75)',
  ink: 'oklch(0.22 0.01 80)',
  inkSoft: 'oklch(0.38 0.01 80)',
  olive: 'oklch(0.55 0.08 110)',
  oliveDeep: 'oklch(0.40 0.07 110)',
};

// ─── One-time global styles ─────────────────────────────────
if (typeof document !== 'undefined' && !document.getElementById('gs-styles')) {
  const s = document.createElement('style');
  s.id = 'gs-styles';
  s.textContent = `
    @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600;700;800&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&family=JetBrains+Mono:wght@400;500&display=swap');

    .gs-root {
      font-family: 'Cormorant Garamond', Georgia, serif;
      color: ${GREEK.ink};
      background:
        radial-gradient(ellipse at 50% 0%, oklch(0.95 0.02 80) 0%, transparent 60%),
        radial-gradient(ellipse at 0% 100%, oklch(0.88 0.03 75) 0%, transparent 50%),
        radial-gradient(ellipse at 100% 100%, oklch(0.90 0.025 85) 0%, transparent 50%),
        ${GREEK.parchment};
      position: relative;
      overflow: hidden;
      height: 100%;
      width: 100%;
      isolation: isolate;
    }
    .gs-root::before {
      content: '';
      position: absolute; inset: 0;
      background-image:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.2 0 0 0 0 0.15 0 0 0 0 0.1 0 0 0 0.15 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
      opacity: 0.4;
      mix-blend-mode: multiply;
      pointer-events: none;
      z-index: 0;
    }
    .gs-root::after {
      content: '';
      position: absolute; inset: 0;
      background-image:
        radial-gradient(circle at 20% 30%, oklch(0.75 0.04 60 / 0.15) 0%, transparent 30%),
        radial-gradient(circle at 80% 70%, oklch(0.70 0.05 70 / 0.12) 0%, transparent 25%);
      pointer-events: none;
      z-index: 0;
    }
    .gs-root > * { position: relative; z-index: 1; }

    .gs-cinzel { font-family: 'Cinzel', serif; letter-spacing: 0.04em; }
    .gs-mono { font-family: 'JetBrains Mono', 'Courier New', monospace; }
    .gs-italic { font-style: italic; }

    /* Greek-key / meander border via repeating background */
    .gs-meander {
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='12' viewBox='0 0 40 12'%3E%3Cpath d='M0 11 L0 1 L9 1 L9 7 L4 7 L4 4 L6 4 L6 5 M11 1 L20 1 L20 11 L11 11 L11 8 L17 8 L17 3 L13 3 L13 5 M22 11 L22 1 L31 1 L31 7 L26 7 L26 4 L28 4 L28 5 M33 1 L40 1' fill='none' stroke='${encodeURIComponent(GREEK.goldDeep)}' stroke-width='1.5'/%3E%3C/svg%3E");
      background-repeat: repeat-x;
      background-size: 40px 12px;
      height: 12px;
    }

    /* Column — fluted */
    .gs-column {
      position: relative;
      background:
        linear-gradient(90deg,
          oklch(0.85 0.02 80) 0%,
          oklch(0.95 0.01 80) 8%,
          oklch(0.92 0.01 80) 14%,
          oklch(0.97 0.005 80) 22%,
          oklch(0.93 0.01 80) 30%,
          oklch(0.96 0.005 80) 42%,
          oklch(0.92 0.015 80) 50%,
          oklch(0.96 0.005 80) 58%,
          oklch(0.93 0.01 80) 70%,
          oklch(0.97 0.005 80) 78%,
          oklch(0.92 0.01 80) 86%,
          oklch(0.95 0.01 80) 92%,
          oklch(0.85 0.02 80) 100%);
      box-shadow:
        inset 0 0 0 1px oklch(0.78 0.02 75 / 0.3),
        0 0 20px oklch(0.75 0.04 70 / 0.15);
    }
    .gs-column::before, .gs-column::after {
      content: '';
      position: absolute;
      left: -12%; right: -12%;
      height: 18px;
      background: linear-gradient(180deg,
        oklch(0.85 0.02 75) 0%,
        oklch(0.96 0.01 80) 50%,
        oklch(0.82 0.025 75) 100%);
      box-shadow: 0 1px 0 oklch(0.70 0.03 70 / 0.4);
    }
    .gs-column::before { top: 0; }
    .gs-column::after { bottom: 0; }

    /* Engraved gold button */
    .gs-btn-gold {
      font-family: 'Cinzel', serif;
      letter-spacing: 0.12em;
      font-weight: 700;
      text-transform: uppercase;
      background:
        linear-gradient(180deg,
          oklch(0.85 0.13 80) 0%,
          oklch(0.72 0.14 78) 50%,
          oklch(0.58 0.13 75) 100%);
      color: oklch(0.25 0.08 60);
      border: 1.5px solid oklch(0.50 0.12 70);
      box-shadow:
        inset 0 1px 0 oklch(0.95 0.10 85 / 0.7),
        inset 0 -2px 0 oklch(0.45 0.10 65 / 0.4),
        0 2px 0 oklch(0.45 0.10 65),
        0 6px 18px oklch(0.50 0.10 70 / 0.35);
      cursor: pointer;
      transition: transform 0.08s ease, box-shadow 0.08s ease;
      text-shadow: 0 1px 0 oklch(0.92 0.08 85 / 0.6);
    }
    .gs-btn-gold:hover {
      transform: translateY(-1px);
      box-shadow:
        inset 0 1px 0 oklch(0.95 0.10 85 / 0.8),
        inset 0 -2px 0 oklch(0.45 0.10 65 / 0.4),
        0 3px 0 oklch(0.45 0.10 65),
        0 10px 28px oklch(0.50 0.10 70 / 0.45);
    }
    .gs-btn-gold:active {
      transform: translateY(2px);
      box-shadow:
        inset 0 1px 0 oklch(0.95 0.10 85 / 0.5),
        inset 0 1px 4px oklch(0.40 0.10 65 / 0.4),
        0 0 0 oklch(0.45 0.10 65);
    }

    /* Wine button */
    .gs-btn-wine {
      font-family: 'Cinzel', serif;
      letter-spacing: 0.1em;
      font-weight: 600;
      text-transform: uppercase;
      background: linear-gradient(180deg, ${GREEK.wine}, ${GREEK.wineDeep});
      color: oklch(0.92 0.04 80);
      border: 1px solid ${GREEK.wineDeep};
      box-shadow:
        inset 0 1px 0 oklch(0.55 0.10 25 / 0.5),
        0 2px 0 ${GREEK.wineDeep},
        0 6px 14px oklch(0.30 0.12 25 / 0.4);
      cursor: pointer;
      transition: transform 0.08s ease;
    }
    .gs-btn-wine:hover { transform: translateY(-1px); }
    .gs-btn-wine:active { transform: translateY(2px); box-shadow: inset 0 1px 4px ${GREEK.wineDeep}; }

    /* Ghost button */
    .gs-btn-ghost {
      font-family: 'Cinzel', serif;
      letter-spacing: 0.1em;
      font-weight: 500;
      text-transform: uppercase;
      background: transparent;
      color: ${GREEK.ink};
      border: 1.5px solid ${GREEK.ink};
      cursor: pointer;
      transition: all 0.12s;
    }
    .gs-btn-ghost:hover { background: ${GREEK.ink}; color: ${GREEK.marble}; }

    /* Input */
    .gs-input {
      font-family: 'Cormorant Garamond', Georgia, serif;
      background: oklch(0.97 0.005 80 / 0.7);
      border: none;
      border-bottom: 1.5px solid ${GREEK.ink};
      padding: 6px 8px;
      font-size: 18px;
      color: ${GREEK.ink};
      outline: none;
      width: 100%;
      transition: border-color 0.15s;
    }
    .gs-input:focus { border-color: ${GREEK.wine}; background: oklch(0.99 0.005 80); }

    /* Animations */
    @keyframes gs-fadein { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
    @keyframes gs-flip-in { from { opacity: 0; transform: rotateY(90deg) scale(0.8); } to { opacity: 1; transform: rotateY(0) scale(1); } }
    @keyframes gs-pulse-glow { 0%,100% { box-shadow: 0 0 0 0 oklch(0.78 0.13 80 / 0.6); } 50% { box-shadow: 0 0 0 12px oklch(0.78 0.13 80 / 0); } }
    @keyframes gs-spin { to { transform: rotate(360deg); } }
    @keyframes gs-shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
    @keyframes gs-shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
    @keyframes gs-confetti-fall { to { transform: translate3d(var(--gs-tx,0), 110vh, 0) rotate(var(--gs-tr,720deg)); opacity: 0; } }

    .gs-fadein { animation: gs-fadein 0.4s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
    .gs-flip-in { animation: gs-flip-in 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) both; transform-style: preserve-3d; perspective: 800px; }
    .gs-pulse { animation: gs-pulse-glow 2s ease-in-out infinite; }
    .gs-shake { animation: gs-shake 0.3s ease-in-out; }

    /* Drink-o-meter (amphora fill) */
    .gs-amphora-fill {
      background: linear-gradient(180deg, ${GREEK.wine} 0%, ${GREEK.wineDeep} 100%);
      background-size: 200% 100%;
      animation: gs-shimmer 3s linear infinite;
    }

    /* Striped placeholder */
    .gs-placeholder {
      background:
        repeating-linear-gradient(135deg,
          oklch(0.88 0.02 80) 0,
          oklch(0.88 0.02 80) 8px,
          oklch(0.82 0.025 75) 8px,
          oklch(0.82 0.025 75) 16px);
      display: flex;
      align-items: center;
      justify-content: center;
      font-family: 'JetBrains Mono', monospace;
      font-size: 10px;
      color: oklch(0.50 0.04 70);
      letter-spacing: 0.05em;
      text-transform: uppercase;
    }

    /* Card */
    .gs-card {
      background:
        linear-gradient(180deg, oklch(0.98 0.005 80) 0%, oklch(0.93 0.015 80) 100%);
      box-shadow:
        0 1px 0 oklch(1 0 0 / 0.6) inset,
        0 -1px 0 oklch(0.7 0.03 70 / 0.3) inset,
        0 10px 30px oklch(0.4 0.05 70 / 0.18),
        0 30px 60px oklch(0.4 0.05 70 / 0.12);
      border: 1px solid oklch(0.78 0.03 75 / 0.5);
    }
  `;
  document.head.appendChild(s);
}

// ─── Decorative primitives ──────────────────────────────────
const GsColumn = ({ side = 'left', style = {} }) => (
  <div className="gs-column" style={{
    position: 'absolute',
    top: 40, bottom: 40,
    width: 24,
    [side]: 18,
    zIndex: 1,
    ...style,
  }} />
);

const GsMeander = ({ style = {} }) => (
  <div className="gs-meander" style={style} />
);

// Striped placeholder for imagery (marble bust, laurel etc.)
const GsImg = ({ w, h, label, round = false, style = {} }) => (
  <div className="gs-placeholder" style={{
    width: w, height: h,
    borderRadius: round ? '50%' : 4,
    ...style,
  }}>{label}</div>
);

// Drink-o-meter — amphora-shaped progress bar
const GsDrinkOMeter = ({ value, max = 100, label = 'Libations' }) => {
  const pct = Math.min(100, (value / max) * 100);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      <span className="gs-cinzel" style={{ fontSize: 10, fontWeight: 600, color: GREEK.inkSoft, letterSpacing: '0.15em' }}>
        {label.toUpperCase()}
      </span>
      <div style={{
        flex: 1,
        height: 14,
        background: oklch_bg(0.85, 0.02, 75),
        border: `1px solid ${GREEK.parchmentDeep}`,
        borderRadius: 2,
        overflow: 'hidden',
        boxShadow: 'inset 0 1px 3px oklch(0.6 0.03 70 / 0.3)',
        position: 'relative',
      }}>
        <div className="gs-amphora-fill" style={{
          width: `${pct}%`,
          height: '100%',
          transition: 'width 0.5s cubic-bezier(0.2, 0.7, 0.3, 1)',
        }} />
        <div style={{
          position: 'absolute', inset: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontSize: 10, fontWeight: 700,
          color: pct > 40 ? GREEK.marble : GREEK.ink,
          fontFamily: 'JetBrains Mono, monospace',
          mixBlendMode: pct > 40 ? 'normal' : 'normal',
          textShadow: pct > 40 ? '0 1px 0 rgba(0,0,0,0.3)' : 'none',
        }}>{value} / {max}</div>
      </div>
    </div>
  );
};

function oklch_bg(l, c, h) { return `oklch(${l} ${c} ${h})`; }

// ─── Sounds (WebAudio) ──────────────────────────────────────
let _gsAudioCtx = null;
const gsAudio = () => {
  if (!_gsAudioCtx) {
    try { _gsAudioCtx = new (window.AudioContext || window.webkitAudioContext)(); } catch {}
  }
  return _gsAudioCtx;
};
const gsPlayTone = (freq, dur = 0.15, type = 'sine', gain = 0.15) => {
  const ctx = gsAudio(); if (!ctx) return;
  const t = ctx.currentTime;
  const osc = ctx.createOscillator();
  const g = ctx.createGain();
  osc.frequency.value = freq;
  osc.type = type;
  g.gain.setValueAtTime(0, t);
  g.gain.linearRampToValueAtTime(gain, t + 0.01);
  g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
  osc.connect(g); g.connect(ctx.destination);
  osc.start(t); osc.stop(t + dur + 0.02);
};
const gsSounds = {
  click: () => gsPlayTone(660, 0.07, 'triangle', 0.08),
  reveal: () => { gsPlayTone(440, 0.1, 'sine', 0.12); setTimeout(() => gsPlayTone(660, 0.12, 'sine', 0.12), 80); setTimeout(() => gsPlayTone(880, 0.18, 'sine', 0.10), 180); },
  ding: () => { gsPlayTone(880, 0.08, 'sine', 0.12); setTimeout(() => gsPlayTone(1320, 0.18, 'sine', 0.10), 60); },
  err: () => gsPlayTone(180, 0.18, 'sawtooth', 0.10),
  drink: () => { gsPlayTone(220, 0.4, 'sine', 0.18); },
  spin: () => {
    const ctx = gsAudio(); if (!ctx) return;
    for (let i = 0; i < 8; i++) {
      setTimeout(() => gsPlayTone(440 - i * 20, 0.05, 'square', 0.04), i * 90);
    }
  },
  win: () => {
    [523, 659, 784, 1047].forEach((f, i) => setTimeout(() => gsPlayTone(f, 0.2, 'triangle', 0.12), i * 90));
  },
};

// ─── Confetti (laurel leaves + gold flecks) ─────────────────
function GsConfetti({ active, count = 60 }) {
  if (!active) return null;
  const pieces = React.useMemo(() => {
    return Array.from({ length: count }, (_, i) => ({
      id: i,
      x: Math.random() * 100,
      delay: Math.random() * 0.6,
      dur: 1.4 + Math.random() * 1.4,
      tx: (Math.random() - 0.5) * 200,
      tr: (Math.random() - 0.5) * 1440,
      size: 6 + Math.random() * 10,
      kind: Math.random() < 0.5 ? 'gold' : 'leaf',
      hueOffset: Math.random() * 20 - 10,
    }));
  }, [active, count]);
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', overflow: 'hidden', zIndex: 100 }}>
      {pieces.map((p) => (
        <div key={p.id} style={{
          position: 'absolute',
          top: -20,
          left: `${p.x}%`,
          width: p.size,
          height: p.size * (p.kind === 'leaf' ? 1.8 : 1),
          background: p.kind === 'gold'
            ? `oklch(${0.75 + p.hueOffset / 200} 0.14 ${80 + p.hueOffset})`
            : `oklch(${0.55 + p.hueOffset / 200} 0.10 ${110 + p.hueOffset})`,
          borderRadius: p.kind === 'leaf' ? '50% 0' : 2,
          animation: `gs-confetti-fall ${p.dur}s ease-in ${p.delay}s forwards`,
          '--gs-tx': `${p.tx}px`,
          '--gs-tr': `${p.tr}deg`,
        }} />
      ))}
    </div>
  );
}

// ─── Buttons ────────────────────────────────────────────────
const GsButton = ({ kind = 'gold', children, onClick, sound = 'click', style = {}, disabled, type = 'button', ...rest }) => {
  const cls = kind === 'wine' ? 'gs-btn-wine' : kind === 'ghost' ? 'gs-btn-ghost' : 'gs-btn-gold';
  return (
    <button type={type} disabled={disabled}
      className={cls}
      onClick={(e) => {
        if (sound && gsSounds[sound]) gsSounds[sound]();
        onClick && onClick(e);
      }}
      style={{
        padding: '14px 28px',
        fontSize: 14,
        borderRadius: 2,
        opacity: disabled ? 0.4 : 1,
        cursor: disabled ? 'not-allowed' : 'pointer',
        ...style,
      }}
      {...rest}
    >{children}</button>
  );
};

// ─── Frame wrapper (column-on-sides, meander top/bottom) ────
const GsFrame = ({ children, style = {} }) => (
  <div className="gs-root" style={style}>
    <GsMeander style={{ position: 'absolute', top: 14, left: 50, right: 50, zIndex: 2 }} />
    <GsMeander style={{ position: 'absolute', bottom: 14, left: 50, right: 50, transform: 'rotate(180deg)', zIndex: 2 }} />
    <GsColumn side="left" />
    <GsColumn side="right" />
    <div style={{
      position: 'absolute',
      top: 38, bottom: 38, left: 70, right: 70,
      zIndex: 2,
      display: 'flex',
      flexDirection: 'column',
    }}>
      {children}
    </div>
  </div>
);

// ─── Player avatar (named circle) ───────────────────────────
const GsAvatar = ({ name, size = 40, active = false, color }) => {
  const initials = (name || '?').slice(0, 2).toUpperCase();
  // Generate stable color from name
  let h = 0;
  for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) | 0;
  const hue = color || (Math.abs(h) % 360);
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: `linear-gradient(135deg, oklch(0.70 0.08 ${hue}), oklch(0.55 0.10 ${hue}))`,
      color: 'oklch(0.98 0.01 80)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontFamily: 'Cinzel, serif',
      fontWeight: 700, fontSize: size * 0.35,
      letterSpacing: '0.05em',
      boxShadow: active
        ? `0 0 0 3px ${GREEK.gold}, 0 4px 12px oklch(0.50 0.08 ${hue} / 0.4)`
        : '0 2px 6px oklch(0.40 0.05 70 / 0.25)',
      flexShrink: 0,
      transition: 'box-shadow 0.2s, transform 0.2s',
      transform: active ? 'scale(1.08)' : 'scale(1)',
    }}>{initials}</div>
  );
};

// Export to window for cross-script-file usage.
Object.assign(window, {
  GREEK, GsColumn, GsMeander, GsImg, GsDrinkOMeter, GsConfetti,
  GsButton, GsFrame, GsAvatar, gsSounds,
});
