/* ============================================================
   seal.jsx — 金印モチーフ & 捺印アニメーション
   Geometric concentric-ring seal (option A) rendered as SVG.
   ============================================================ */

const { useState, useRef, useEffect, useCallback } = React;

/* Seal-script style tick marks around a ring */
function TickRing({ r, count, len, w, cx, cy, opacity }) {
  const ticks = [];
  for (let i = 0; i < count; i++) {
    const a = (i / count) * Math.PI * 2 - Math.PI / 2;
    const x1 = cx + Math.cos(a) * r;
    const y1 = cy + Math.sin(a) * r;
    const x2 = cx + Math.cos(a) * (r + len);
    const y2 = cy + Math.sin(a) * (r + len);
    ticks.push(
      <line key={i} x1={x1} y1={y1} x2={x2} y2={y2}
        stroke="url(#sealFoil)" strokeWidth={w} strokeLinecap="butt" opacity={opacity} />
    );
  }
  return <g>{ticks}</g>;
}

/*
  SealMark — the digital 金印.
  variant: 'glow' (hero, with rotating rings + glow) | 'flat' (decorative) | 'solid' (filled chip)
  size in px.
*/
function SealMark({ size = 360, variant = 'glow', label = '印', strokeOnly = false }) {
  const cx = 100, cy = 100;
  return (
    <div className="seal" style={{ width: size, height: size }}>
      {variant === 'glow' && <div className="seal-glow" />}
      <svg width={size} height={size} viewBox="0 0 200 200" aria-hidden="true">
        <defs>
          <linearGradient id="sealFoil" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" stopColor="#B8923A" />
            <stop offset="30%" stopColor="#E8C97A" />
            <stop offset="52%" stopColor="#F4E4B0" />
            <stop offset="70%" stopColor="#C9A84C" />
            <stop offset="100%" stopColor="#9C7A2C" />
          </linearGradient>
          <radialGradient id="sealCore" cx="50%" cy="42%" r="65%">
            <stop offset="0%" stopColor="#E8C97A" />
            <stop offset="60%" stopColor="#C9A84C" />
            <stop offset="100%" stopColor="#9C7A2C" />
          </radialGradient>
        </defs>

        {/* outer rotating tick ring */}
        <g className={variant === 'glow' ? 'ring-rotate' : ''} style={{ transformOrigin: '100px 100px' }}>
          <TickRing r={88} count={72} len={6} w={1.4} cx={cx} cy={cy} opacity={0.9} />
        </g>
        {/* fixed rings */}
        <circle cx={cx} cy={cy} r={80} fill="none" stroke="url(#sealFoil)" strokeWidth="2.5" />
        <circle cx={cx} cy={cy} r={72} fill="none" stroke="url(#sealFoil)" strokeWidth="1" opacity="0.6" />

        {/* inner rotating fine ring */}
        <g className={variant === 'glow' ? 'ring-rotate-rev' : ''} style={{ transformOrigin: '100px 100px' }}>
          <TickRing r={58} count={48} len={3.5} w={1} cx={cx} cy={cy} opacity={0.7} />
        </g>
        <circle cx={cx} cy={cy} r={52} fill="none" stroke="url(#sealFoil)" strokeWidth="1.6" />

        {/* center square + glyph */}
        {strokeOnly ? (
          <rect x={74} y={74} width={52} height={52} rx="3" fill="none" stroke="url(#sealFoil)" strokeWidth="2.5" />
        ) : (
          <rect x={74} y={74} width={52} height={52} rx="3" fill="url(#sealCore)" />
        )}
        <text x={cx} y={cy + 13} textAnchor="middle"
          fontFamily="'Noto Serif JP', serif" fontWeight="700" fontSize="38"
          fill={strokeOnly ? 'url(#sealFoil)' : '#0D1F0F'}>{label}</text>

        {/* corner registration marks */}
        {[[100, 8], [100, 192], [8, 100], [192, 100]].map(([x, y], i) => (
          <circle key={i} cx={x} cy={y} r="2" fill="url(#sealFoil)" opacity="0.8" />
        ))}
      </svg>
    </div>
  );
}

/*
  StampButton — interactive 捺印 demo.
  Click → the seal drops onto the target, ink ripple, leaves an impression.
*/
function StampButton({ size = 150, label = '印', caption = 'クリックで押印', dark = false }) {
  const [pressed, setPressed] = useState(false);
  const [stamped, setStamped] = useState(false);
  const sealRef = useRef(null);
  const rippleRef = useRef(null);

  const press = useCallback(() => {
    const seal = sealRef.current;
    const rip = rippleRef.current;
    if (!seal) return;
    seal.classList.remove('stamp-play');
    void seal.offsetWidth;
    seal.classList.add('stamp-play');
    if (rip) { rip.classList.remove('play'); void rip.offsetWidth; rip.classList.add('play'); }
    setPressed(true);
    setTimeout(() => setStamped(true), 360);
  }, []);

  const reset = useCallback((e) => { e.stopPropagation(); setStamped(false); setPressed(false); }, []);

  return (
    <div style={{ display: 'grid', placeItems: 'center', gap: 14 }}>
      <div
        onClick={press}
        style={{
          position: 'relative', width: size, height: size, cursor: 'pointer',
          display: 'grid', placeItems: 'center',
        }}
        role="button" aria-label="押印する">
        {/* impression target (faint) */}
        <div className={'impression' + (stamped ? ' show' : '')}
          style={{
            position: 'absolute', inset: '6%', borderRadius: '50%',
            border: `2px solid ${dark ? 'rgba(232,201,122,.45)' : 'rgba(168,134,47,.4)'}`,
            display: 'grid', placeItems: 'center',
          }}>
          <span className="serif" style={{ fontSize: size * 0.26, color: dark ? 'rgba(232,201,122,.5)' : 'rgba(168,134,47,.45)', fontWeight: 700 }}>{label}</span>
        </div>
        <div ref={rippleRef} className="ink-ripple" style={{ inset: '4%' }} />
        {/* the physical seal that presses down */}
        <div ref={sealRef} style={{ filter: 'drop-shadow(0 12px 18px rgba(10,24,12,.4))' }}>
          <SealMark size={size} variant="flat" label={label} />
        </div>
      </div>
      <span style={{ fontSize: 12, letterSpacing: '0.18em', color: dark ? 'var(--gold-light)' : 'var(--ink-soft)' }}>
        {stamped ? <button onClick={reset} style={{ color: 'var(--gold-deep)', fontWeight: 600, letterSpacing: '0.1em' }}>↺ もう一度</button> : caption}
      </span>
    </div>
  );
}

Object.assign(window, { SealMark, StampButton, TickRing, whenClockAlive, autoStampSafe });

/* Runs cb only after two animation frames actually advance — i.e. the
   animation clock is alive. In frozen/throttled environments rAF never
   fires, so cb is skipped and elements keep their visible default state
   instead of freezing on an animation's first (hidden) keyframe. */
function whenClockAlive(cb) {
  let r1 = 0, r2 = 0;
  r1 = requestAnimationFrame(() => { r2 = requestAnimationFrame(cb); });
  return () => { cancelAnimationFrame(r1); cancelAnimationFrame(r2); };
}

/* Plays the 捺印 entrance on a seal element, but with a safety net: rAF can
   fire while the CSS animation clock is frozen, which would leave the seal
   stuck on stampDrop's 0% keyframe (opacity 0). If the seal is still
   invisible shortly after, strip the class so it snaps to its visible
   default. getEl is called lazily (ref may not be set yet). */
function autoStampSafe(getEl) {
  return whenClockAlive(() => {
    const el = getEl();
    if (!el) return;
    el.classList.remove('stamp-play');
    void el.offsetWidth;
    el.classList.add('stamp-play');
    setTimeout(() => {
      if (el && parseFloat(getComputedStyle(el).opacity) < 0.02) {
        el.classList.remove('stamp-play');
      }
    }, 1000);
  });
}
