// video-kit.jsx — shared building blocks for AIWine "Discover" explainer reels.
// Load AFTER animations.jsx. Exposes palette, helpers and reusable SVG
// components on window so each reel's inline scene script can use them.

const { useTime, Easing, animate, clamp } = window;

/* palette + type */
const C = {
  bone:'#F4EFE5', boneAlt:'#E7DcC8', card:'#FAF6EE',
  ink:'#1B1410', inkSoft:'#4A3D34', muted:'#8B7E6E',
  claret:'#5C1B27', claretDeep:'#3A0E18', brass:'#A98654', brassSoft:'#C9A878',
  amberTop:'#E0A24E', amberBot:'#B26B22',
  redTop:'#7A2230', redBot:'#3A0E18',
  whiteTop:'#ECDCA0', whiteBot:'#D4BC72',
  roseTop:'#E6A6B2', roseBot:'#C66C81',
  bottleGlass:'#33442C', bottleGlassHi:'#4C6140',
  cork:'#C9A35E', corkShade:'#A98442',
  grape:'#C9C887', grapeShade:'#A9A85E',
};
const SERIF='"Cormorant Garamond",Georgia,serif';
const SANS='"Manrope",system-ui,sans-serif';
const MONO='"JetBrains Mono",monospace';
const W=1080, H=1920;

/* helpers */
const ease=(t,a,b,from,to,fn=Easing.easeOutCubic)=>animate({from,to,start:a,end:b,ease:fn})(t);
function fade(t,inA,inB,outA,outB){
  if(t<inA) return 0;
  if(t<inB) return Easing.easeOutCubic((t-inA)/(inB-inA));
  if(outA==null||t<outA) return 1;
  if(t<outB) return 1-Easing.easeInCubic((t-outA)/(outB-outA));
  return 0;
}
function lerpHex(a,b,t){
  const pa=[parseInt(a.slice(1,3),16),parseInt(a.slice(3,5),16),parseInt(a.slice(5,7),16)];
  const pb=[parseInt(b.slice(1,3),16),parseInt(b.slice(3,5),16),parseInt(b.slice(5,7),16)];
  const c=pa.map((v,i)=>Math.round(v+(pb[i]-v)*clamp(t,0,1)));
  return `#${c.map(v=>v.toString(16).padStart(2,'0')).join('')}`;
}

/* background */
function Bg(){
  const t=useTime();
  const drift=Math.sin(t*0.18)*14;
  return (
    <div style={{position:'absolute',inset:0,overflow:'hidden',
      background:`linear-gradient(178deg, ${C.bone} 0%, ${C.boneAlt} 100%)`}}>
      <div style={{position:'absolute',left:'50%',top:-260+drift,width:1400,height:1100,
        transform:'translateX(-50%)',borderRadius:'50%',
        background:`radial-gradient(closest-side, ${C.claret}22, transparent 70%)`}}/>
      <div style={{position:'absolute',left:'50%',bottom:-360-drift,width:1500,height:1100,
        transform:'translateX(-50%)',borderRadius:'50%',
        background:`radial-gradient(closest-side, ${C.brass}1f, transparent 70%)`}}/>
    </div>
  );
}

/* wine glass — level 0..1, gradient top/bot */
function WineGlass({level=0, top=C.amberTop, bot=C.amberBot, scale=1, sway=0, x=0, y=0, opacity=1, glow=false, id='g'}){
  const surfaceY=255-clamp(level,0,1)*(255-58);
  const rx=92*(1-(surfaceY-45)/210);
  const grad=`grad_${id}`;
  return (
    <div style={{position:'absolute',left:'50%',top:'50%',
      transform:`translate(-50%,-50%) translate(${x}px,${y}px) rotate(${sway}deg) scale(${scale})`,
      transformOrigin:'50% 60%',opacity,willChange:'transform,opacity'}}>
      <svg width="300" height="420" viewBox="0 0 300 420">
        <defs>
          <linearGradient id={grad} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor={top}/><stop offset="1" stopColor={bot}/>
          </linearGradient>
          <clipPath id={`clip_${id}`}>
            <path d="M58,48 L242,48 C242,182 198,252 150,256 C102,252 58,182 58,48 Z"/>
          </clipPath>
        </defs>
        {glow && <ellipse cx="150" cy="150" rx="140" ry="150" fill={top} opacity="0.18"/>}
        <g clipPath={`url(#clip_${id})`}>
          <rect x="50" y={surfaceY} width="200" height={260} fill={`url(#${grad})`}/>
          <ellipse cx="150" cy={surfaceY} rx={Math.max(0,rx)} ry="9" fill={top} opacity="0.9"/>
          <ellipse cx="150" cy={surfaceY} rx={Math.max(0,rx*0.8)} ry="5" fill="#fff" opacity="0.18"/>
        </g>
        <path d="M58,48 L242,48 C242,182 198,252 150,256 C102,252 58,182 58,48"
          fill="none" stroke={C.ink} strokeOpacity="0.55" strokeWidth="3.5" strokeLinejoin="round"/>
        <line x1="150" y1="256" x2="150" y2="372" stroke={C.ink} strokeOpacity="0.55" strokeWidth="3.5"/>
        <path d="M92,388 Q150,372 208,388" fill="none" stroke={C.ink} strokeOpacity="0.55" strokeWidth="3.5" strokeLinecap="round"/>
        <path d="M86,80 Q80,150 110,210" fill="none" stroke="#fff" strokeOpacity="0.28" strokeWidth="7" strokeLinecap="round"/>
      </svg>
    </div>
  );
}

/* wine bottle — corkOut 0..1 lifts the cork out of the neck */
function Bottle({x=0,y=0,scale=1,opacity=1,tilt=0,corkOut=0,glass=C.bottleGlass,label=true,id='b'}){
  const corkY=44-corkOut*66;
  return (
    <div style={{position:'absolute',left:'50%',top:'50%',
      transform:`translate(-50%,-50%) translate(${x}px,${y}px) rotate(${tilt}deg) scale(${scale})`,
      transformOrigin:'50% 70%',opacity,willChange:'transform,opacity'}}>
      <svg width="200" height="540" viewBox="0 0 200 540">
        <defs>
          <linearGradient id={`bg_${id}`} x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" stopColor={glass}/>
            <stop offset="0.5" stopColor={C.bottleGlassHi}/>
            <stop offset="1" stopColor={glass}/>
          </linearGradient>
        </defs>
        {/* body */}
        <path d="M58,200 L58,488 Q58,512 82,512 L118,512 Q142,512 142,488 L142,200
                 C142,162 114,156 114,120 L86,120 C86,156 58,162 58,200 Z"
          fill={`url(#bg_${id})`} stroke={C.ink} strokeOpacity="0.5" strokeWidth="3"/>
        {/* neck */}
        <rect x="86" y="70" width="28" height="54" fill={`url(#bg_${id})`} stroke={C.ink} strokeOpacity="0.5" strokeWidth="3"/>
        {/* cork */}
        <rect x="87" y={corkY} width="26" height="34" rx="5" fill={C.cork} stroke={C.corkShade} strokeWidth="2"/>
        <line x1="87" y1={corkY+12} x2="113" y2={corkY+12} stroke={C.corkShade} strokeWidth="1.5" opacity="0.6"/>
        {/* label */}
        {label && <g>
          <rect x="64" y="300" width="72" height="104" rx="6" fill={C.bone} opacity="0.95"/>
          <line x1="78" y1="330" x2="122" y2="330" stroke={C.claret} strokeWidth="4" strokeLinecap="round"/>
          <line x1="84" y1="352" x2="116" y2="352" stroke={C.brass} strokeWidth="3" strokeLinecap="round"/>
          <line x1="88" y1="372" x2="112" y2="372" stroke={C.muted} strokeWidth="2.5" strokeLinecap="round"/>
        </g>}
        {/* highlight */}
        <path d="M74,150 Q66,330 80,490" fill="none" stroke="#fff" strokeOpacity="0.22" strokeWidth="8" strokeLinecap="round"/>
      </svg>
    </div>
  );
}

/* grape cluster */
function Grapes({x=0,y=0,scale=1,opacity=1,t=0}){
  const pts=[[0,0],[-34,4],[34,4],[-62,34],[0,30],[62,34],[-34,62],[34,62],[0,90],[-30,118],[30,118],[0,146]];
  return (
    <div style={{position:'absolute',left:'50%',top:'50%',
      transform:`translate(-50%,-50%) translate(${x}px,${y}px) scale(${scale})`,opacity}}>
      <svg width="220" height="280" viewBox="-90 -40 220 280">
        <path d="M0,-10 q10,-22 4,-36" fill="none" stroke={C.brass} strokeWidth="6" strokeLinecap="round"/>
        <path d="M4,-44 q34,-14 54,8 q-30,18 -54,-8 Z" fill={C.grapeShade} opacity="0.9"/>
        {pts.map((p,i)=>{const bob=Math.sin(t*2+i*0.6)*2;return <g key={i}>
          <circle cx={p[0]} cy={p[1]+bob} r="22" fill={C.grape}/>
          <circle cx={p[0]-6} cy={p[1]-6+bob} r="7" fill="#fff" opacity="0.35"/></g>;})}
      </svg>
    </div>
  );
}

/* price tag */
function PriceTag({price, x=0, y=0, scale=1, opacity=1, rot=-8}){
  return (
    <div style={{position:'absolute',left:'50%',top:'50%',
      transform:`translate(-50%,-50%) translate(${x}px,${y}px) rotate(${rot}deg) scale(${scale})`,opacity}}>
      <svg width="240" height="150" viewBox="0 0 240 150">
        <path d="M40,8 L228,8 Q236,8 236,16 L236,134 Q236,142 228,142 L40,142
                 Q34,142 30,137 L6,80 Q4,75 6,70 L30,13 Q34,8 40,8 Z" fill={C.claret}/>
        <circle cx="44" cy="75" r="11" fill={C.bone}/>
        <text x="138" y="98" textAnchor="middle" fontFamily={SERIF} fontWeight="700" fontSize="76" fill={C.bone}>{price}</text>
      </svg>
    </div>
  );
}

/* captions + kickers */
function Caption({children,t,inA,inB,outA,outB,y=1560,size=58,weight=600,color=C.ink,font=SANS,style={}}){
  const o=fade(t,inA,inB,outA,outB);
  const up=(1-fade(t,inA,inB,null,null))*26;
  return (
    <div style={{position:'absolute',left:90,right:90,top:y,textAlign:'center',
      fontFamily:font,fontWeight:weight,fontSize:size,lineHeight:1.12,color,
      letterSpacing:'-0.01em',opacity:o,transform:`translateY(${up}px)`,textWrap:'balance',...style}}>{children}</div>
  );
}
function Kicker({children,t,inA,inB,outA,outB,y=300,color=C.brass}){
  const o=fade(t,inA,inB,outA,outB);
  return (
    <div style={{position:'absolute',left:0,right:0,top:y,textAlign:'center',
      fontFamily:MONO,fontSize:30,letterSpacing:'0.24em',textTransform:'uppercase',color,opacity:o}}>{children}</div>
  );
}

/* brand corner + progress + step number */
function BrandCorner(){
  return (
    <div style={{position:'absolute',left:54,top:54,fontFamily:SANS,fontWeight:800,fontSize:38,color:C.ink,opacity:0.85}}>
      AI<span style={{display:'inline-block',width:9,height:9,borderRadius:'50%',background:C.claret,margin:'0 5px',verticalAlign:'middle'}}></span>Wine
    </div>
  );
}
function Progress({duration}){
  const t=useTime();
  return <div style={{position:'absolute',left:0,bottom:0,height:8,width:`${(t/duration)*100}%`,
    background:`linear-gradient(90deg,${C.brass},${C.claret})`}}/>;
}
function StepBadge({n,total,x=0,y=0,opacity=1}){
  return (
    <div style={{position:'absolute',left:'50%',top:'50%',transform:`translate(-50%,-50%) translate(${x}px,${y}px)`,
      opacity,fontFamily:MONO,fontSize:28,letterSpacing:'0.18em',color:C.brass,textTransform:'uppercase'}}>
      {String(n).padStart(2,'0')} <span style={{color:C.muted}}>/ {String(total).padStart(2,'0')}</span>
    </div>
  );
}

/* timestamp label for review comments */
function useTimeLabel(label){
  const t=useTime();
  React.useEffect(()=>{
    const r=document.getElementById('vid-root');
    if(r) r.setAttribute('data-screen-label',label+' · '+t.toFixed(0)+'s');
  },[Math.floor(t)]);
}

/* corner vine flourish */
function VineCorner({flip=false}){
  return (
    <svg width="200" height="200" viewBox="0 0 200 200" style={{transform:flip?'scaleX(-1)':'none'}}>
      <path d="M10,30 C70,40 110,80 120,150" fill="none" stroke={C.brass} strokeOpacity="0.4" strokeWidth="4" strokeLinecap="round"/>
      <path d="M120,150 q24,-6 30,-30" fill="none" stroke={C.brass} strokeOpacity="0.4" strokeWidth="4" strokeLinecap="round"/>
      <circle cx="60" cy="52" r="7" fill={C.brass} opacity="0.4"/>
      <circle cx="86" cy="78" r="7" fill={C.brass} opacity="0.32"/>
      <circle cx="106" cy="112" r="7" fill={C.brass} opacity="0.26"/>
      <path d="M44,28 q26,-14 50,2 q-26,16 -50,-2 Z" fill={C.grapeShade} opacity="0.35"/>
    </svg>
  );
}

/* themed start/end poster behind the centred play / replay button */
function Poster({show, title, sub, accent=C.claret}){
  if(!show) return null;
  return (
    <div style={{position:'absolute',inset:0,zIndex:30,pointerEvents:'none'}}>
      {/* corner flourishes */}
      <div style={{position:'absolute',left:18,top:18}}><VineCorner/></div>
      <div style={{position:'absolute',right:18,top:18}}><VineCorner flip/></div>
      <div style={{position:'absolute',left:18,bottom:18,transform:'scaleY(-1)'}}><VineCorner/></div>
      <div style={{position:'absolute',right:18,bottom:18,transform:'scale(-1,-1)'}}><VineCorner/></div>
      {/* title block (above the centred play button) */}
      <div style={{position:'absolute',left:80,right:80,top:330,textAlign:'center'}}>
        <div style={{fontFamily:MONO,fontSize:28,letterSpacing:'0.26em',textTransform:'uppercase',color:C.brass}}>AIWine · Discover</div>
        <div style={{fontFamily:SERIF,fontWeight:600,fontSize:104,lineHeight:1.0,letterSpacing:'-0.02em',color:accent,marginTop:14}}>{title}</div>
        <div style={{fontFamily:SERIF,fontStyle:'italic',fontSize:48,color:C.inkSoft,marginTop:6}}>{sub}</div>
      </div>
      {/* divider */}
      <div style={{position:'absolute',left:'50%',top:1270,transform:'translateX(-50%)',display:'flex',alignItems:'center',gap:18}}>
        <div style={{width:120,height:2,background:C.brass,opacity:0.5}}/>
        <div style={{width:14,height:14,transform:'rotate(45deg)',background:C.brass,opacity:0.7}}/>
        <div style={{width:120,height:2,background:C.brass,opacity:0.5}}/>
      </div>
      {/* hint + brand */}
      <div style={{position:'absolute',left:0,right:0,top:1560,textAlign:'center',fontFamily:MONO,fontSize:30,letterSpacing:'0.18em',textTransform:'uppercase',color:C.muted}}>Tap to play · 9:16</div>
      <div style={{position:'absolute',left:0,right:0,top:1700,textAlign:'center',fontFamily:SANS,fontWeight:800,fontSize:44,color:C.ink}}>
        AI<span style={{display:'inline-block',width:10,height:10,borderRadius:'50%',background:C.claret,margin:'0 6px',verticalAlign:'middle'}}></span>Wine
      </div>
    </div>
  );
}

/* background music synced to the Stage playhead */
function AudioSync({src, volume=0.55}){
  const { time, playing } = window.useTimeline();
  const ref=React.useRef(null);
  React.useEffect(()=>{ if(ref.current) ref.current.volume=volume; },[volume]);
  React.useEffect(()=>{
    const a=ref.current; if(!a) return;
    if(playing){ a.play().catch(()=>{}); } else { a.pause(); }
  },[playing]);
  // keep audio aligned to the timeline (covers scrub + loop reset)
  React.useEffect(()=>{
    const a=ref.current; if(!a) return;
    if(Math.abs(a.currentTime-time)>0.35){ try{ a.currentTime=time; }catch(e){} }
  });
  return React.createElement('audio',{ref,src,preload:'auto'});
}

Object.assign(window, {
  C, SERIF, SANS, MONO, W, H, ease, fade, lerpHex,
  Bg, WineGlass, Bottle, Grapes, PriceTag, Caption, Kicker, BrandCorner, Progress, StepBadge, useTimeLabel,
  Poster, VineCorner, AudioSync,
});
