// Shared primitive components.
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// Toast system — singleton
let toastId = 0;
let toastSetter = null;
function showToast(msg, opts={}){
  if(!toastSetter) return;
  toastId++;
  toastSetter({ id: toastId, msg, tone: opts.tone || "success" });
  setTimeout(() => toastSetter((cur) => cur && cur.id === toastId ? null : cur), 1800);
}

function ToastHost(){
  const [t, setT] = useState(null);
  useEffect(() => { toastSetter = setT; return () => { toastSetter = null; }; }, []);
  if(!t) return null;
  const tone = t.tone === "success" ? {
    bg: "rgba(0,224,164,0.12)", color: "#3EE8BE", border: "rgba(0,224,164,0.35)"
  } : {
    bg: "rgba(91,140,255,0.12)", color: "#8AB0FF", border: "rgba(91,140,255,0.35)"
  };
  return (
    <div className="toast" style={{background:tone.bg, color:tone.color, borderColor:tone.border}}>
      <span style={{display:"inline-flex",alignItems:"center",gap:8}}>
        <I.check style={{width:14,height:14}}/>
        {t.msg}
      </span>
    </div>
  );
}

// Copy button with inline "Copied!" swap
function CopyButton({ text, label = "Copy", size = "sm", variant = "ghost", icon = true, toastMsg, className = "", style, onCopy }) {
  const [copied, setCopied] = useState(false);
  const handle = async (e) => {
    e.preventDefault();
    e.stopPropagation();
    try {
      await navigator.clipboard.writeText(text);
    } catch {
      // fallback
      const ta = document.createElement("textarea");
      ta.value = text; document.body.appendChild(ta); ta.select();
      document.execCommand("copy"); document.body.removeChild(ta);
    }
    setCopied(true);
    if(toastMsg) showToast(toastMsg);
    onCopy && onCopy();
    setTimeout(() => setCopied(false), 1400);
  };
  const cls = `btn ${variant==="primary"?"btn-primary":""} ${size==="sm"?"btn-sm":""} ${className}`;
  return (
    <button className={cls} onClick={handle} style={style}>
      {icon && (copied ? <I.check style={{width:14,height:14, color:"#3EE8BE"}}/> : <I.copy style={{width:14,height:14}}/>)}
      <span style={{color: copied ? "#3EE8BE" : undefined, transition:"color .15s"}}>
        {copied ? "Copied!" : label}
      </span>
    </button>
  );
}

// Animated number (count-up)
function AnimatedNum({ value, prefix="", suffix="", decimals=0, duration=900 }) {
  const [v, setV] = useState(0);
  const startRef = useRef(null);
  const fromRef = useRef(0);
  useEffect(() => {
    fromRef.current = v;
    startRef.current = performance.now();
    const target = value;
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - startRef.current) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setV(fromRef.current + (target - fromRef.current) * eased);
      if(t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [value]);
  const formatted = v.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
  return <span>{prefix}{formatted}{suffix}</span>;
}

// Sparkline
function Sparkline({ data, color="#5B8CFF", width=120, height=32, fill=true }) {
  const max = Math.max(...data), min = Math.min(...data);
  const range = max - min || 1;
  const stepX = width / (data.length - 1);
  const pts = data.map((v, i) => [i*stepX, height - ((v-min)/range) * (height-4) - 2]);
  const d = pts.map((p,i) => (i===0?"M":"L") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = d + ` L ${width} ${height} L 0 ${height} Z`;
  const gradId = "sg_" + Math.random().toString(36).slice(2,8);
  return (
    <svg width={width} height={height} style={{overflow:"visible"}}>
      <defs>
        <linearGradient id={gradId} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.35"/>
          <stop offset="100%" stopColor={color} stopOpacity="0"/>
        </linearGradient>
      </defs>
      {fill && <path d={area} fill={`url(#${gradId})`}/>}
      <path d={d} fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

// Product "card art" — real image when available, SVG art fallback
function CardArt({ product, size="md" }) {
  const { accent, glyph, kana, motif, imageUrl } = product;
  const tone = {
    crimson:   ["#FF6B8A","#8A2B44"],
    gold:      ["#F6C56B","#8A5E1F"],
    violet:    ["#B89BFF","#4D2E99"],
    teal:      ["#3EE8BE","#0E6A56"],
    blue:      ["#6EA0FF","#1F3E8A"],
    silver:    ["#D6DAE3","#4A5164"],
  }[motif] || ["#6EA0FF","#1F3E8A"];
  const gid = "cga_"+product.id;

  if (imageUrl) {
    return (
      <div className="card-frame" style={{background:"#0B0F1A"}}>
        <img
          src={imageUrl}
          alt={product.name}
          style={{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover"}}
          loading="lazy"
        />
        <div style={{
          position:"absolute",inset:0,pointerEvents:"none",
          background:`linear-gradient(180deg,transparent 55%,rgba(11,15,26,0.85) 100%)`,
        }}/>
      </div>
    );
  }

  return (
    <div className="card-frame" style={{
      background: `radial-gradient(120% 80% at 30% 20%, ${tone[0]}33, transparent 55%),
                   radial-gradient(120% 80% at 80% 90%, ${tone[1]}55, transparent 55%),
                   linear-gradient(180deg,#141A2B,#0E1322)`,
    }}>
      <svg viewBox="0 0 120 160" style={{position:"absolute",inset:0,width:"100%",height:"100%"}}>
        <defs>
          <linearGradient id={gid+"_g"} x1="0" x2="1" y1="0" y2="1">
            <stop offset="0%" stopColor={tone[0]} stopOpacity="0.9"/>
            <stop offset="100%" stopColor={tone[1]} stopOpacity="0.6"/>
          </linearGradient>
          <linearGradient id={gid+"_sheen"} x1="0" x2="1">
            <stop offset="0%" stopColor="#fff" stopOpacity="0"/>
            <stop offset="50%" stopColor="#fff" stopOpacity="0.18"/>
            <stop offset="100%" stopColor="#fff" stopOpacity="0"/>
          </linearGradient>
          <pattern id={gid+"_dots"} width="6" height="6" patternUnits="userSpaceOnUse">
            <circle cx="3" cy="3" r="0.6" fill="#fff" fillOpacity="0.12"/>
          </pattern>
        </defs>
        <rect x="10" y="12" width="100" height="136" rx="6" fill="rgba(255,255,255,0.02)" stroke={tone[0]} strokeOpacity="0.35" strokeWidth="0.6"/>
        <rect x="16" y="22" width="88" height="88" rx="4" fill={`url(#${gid}_g)`} />
        <rect x="16" y="22" width="88" height="88" rx="4" fill={`url(#${gid}_dots)`} />
        <rect x="16" y="22" width="88" height="88" rx="4" fill={`url(#${gid}_sheen)`}/>
        <text x="60" y="72" textAnchor="middle" fontFamily="Sora" fontWeight="800" fontSize="30" fill="rgba(255,255,255,0.92)" style={{letterSpacing:"-0.02em"}}>{glyph}</text>
        <text x="60" y="92" textAnchor="middle" fontFamily="Noto Serif JP" fontWeight="700" fontSize="10" fill="rgba(255,255,255,0.65)">{kana}</text>
        <rect x="16" y="116" width="88" height="26" rx="3" fill="rgba(0,0,0,0.35)" stroke="rgba(255,255,255,0.08)" strokeWidth="0.5"/>
        <text x="22" y="129" fontFamily="JetBrains Mono" fontSize="7" fill="rgba(255,255,255,0.85)" letterSpacing="0.1em">KYOUDAI</text>
        <text x="22" y="138" fontFamily="JetBrains Mono" fontSize="6" fill="rgba(255,255,255,0.5)" letterSpacing="0.15em">JP • SEALED</text>
        <circle cx="94" cy="130" r="4" fill={tone[0]} opacity="0.85"/>
        <circle cx="94" cy="130" r="2" fill="#0B0F1A"/>
      </svg>
      <div style={{
        position:"absolute",inset:0,pointerEvents:"none",
        background: `linear-gradient(120deg, transparent 30%, ${tone[0]}22 48%, transparent 60%)`,
        mixBlendMode:"screen",
      }}/>
    </div>
  );
}

// Video thumb — shows real product image when available
function VideoThumb({ item, onPlay }) {
  const p = window.KYOUDAI.PRODUCTS.find(pr => pr.id === item.productId);
  const hasImg = p && p.imageUrl;
  const typeLabel = (item.type || 'hook').toUpperCase();

  return (
    <div style={{
      position:"relative", aspectRatio:"9/14", borderRadius:14, overflow:"hidden",
      border:"1px solid rgba(255,255,255,0.08)", cursor:"pointer",
      background:"linear-gradient(180deg,#141A2B,#0B0F1A)",
      transition:"transform .3s cubic-bezier(.2,.8,.2,1), border-color .3s",
    }}
    onMouseEnter={e=>{e.currentTarget.style.transform="translateY(-4px)";e.currentTarget.style.borderColor="rgba(91,140,255,0.5)"}}
    onMouseLeave={e=>{e.currentTarget.style.transform="";e.currentTarget.style.borderColor="rgba(255,255,255,0.08)"}}
    onClick={onPlay}
    >
      {/* Real product image */}
      {hasImg
        ? <img src={p.imageUrl} alt={p.name}
            style={{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover"}}/>
        : <div style={{
            position:"absolute",inset:0,
            background:`radial-gradient(140% 80% at 30% 20%, ${item.color}44, transparent 55%),
                        radial-gradient(140% 80% at 80% 90%, ${item.color}77, transparent 60%),
                        #0B0F1A`,
          }}/>
      }

      {/* Gradient overlay — darkens bottom for legibility */}
      <div style={{position:"absolute",inset:0,background:"linear-gradient(180deg, rgba(0,0,0,0.18) 0%, transparent 35%, rgba(0,0,0,0.88) 100%)"}}/>

      {/* Type badge top-left */}
      <div style={{position:"absolute",top:10,left:10,right:10,display:"flex",justifyContent:"space-between",alignItems:"center"}}>
        <span className="mono" style={{
          fontSize:10,fontWeight:700,letterSpacing:"0.12em",
          background:"rgba(0,0,0,0.55)",color:"#fff",border:"1px solid rgba(255,255,255,0.18)",
          backdropFilter:"blur(6px)",padding:"3px 8px",borderRadius:6,
        }}>{typeLabel}</span>
        {item.duration && <span className="mono" style={{fontSize:11,color:"#fff",opacity:.85,background:"rgba(0,0,0,0.45)",padding:"3px 6px",borderRadius:6}}>{item.duration}</span>}
      </div>

      {/* Bottom info */}
      <div style={{position:"absolute",left:12,right:12,bottom:12}}>
        <div style={{fontSize:12,fontWeight:600,color:"#fff",lineHeight:1.3,textWrap:"pretty",marginBottom:6}}>{item.hook}</div>
        <div style={{display:"flex",gap:10,fontSize:10,color:"rgba(255,255,255,0.65)"}} className="mono">
          {item.views !== "0" && <span>▶ {item.views}</span>}
          {item.engagement !== "0%" && <span>♡ {item.engagement}</span>}
        </div>
      </div>
    </div>
  );
}

// Avatar circle
function Avatar({ initials, size=32, tone="#5B8CFF", style }) {
  return (
    <div style={{
      width:size,height:size,borderRadius:99,display:"grid",placeItems:"center",
      background:`linear-gradient(135deg, ${tone}, ${tone}aa)`,
      color:"#fff", fontWeight:700, fontSize:size*0.38, letterSpacing:"-0.02em",
      border:"1px solid rgba(255,255,255,0.1)",
      boxShadow: `0 4px 16px -4px ${tone}99`,
      ...style,
    }}>{initials}</div>
  );
}

// Stat tile
function StatTile({ label, value, prefix="", suffix="", decimals=0, delta, sub, tone="#5B8CFF", icon, spark, className="", style }){
  return (
    <div className={`glass ${className}`} style={{padding:20, position:"relative", overflow:"hidden", ...style}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:14}}>
        <div style={{display:"flex",alignItems:"center",gap:10}}>
          {icon && <div style={{
            width:32,height:32,borderRadius:9,display:"grid",placeItems:"center",
            background:`linear-gradient(135deg, ${tone}33, ${tone}11)`, color: tone,
            border:`1px solid ${tone}33`,
          }}>{icon}</div>}
          <div style={{fontSize:12,color:"var(--sub)",fontWeight:500,letterSpacing:"0.02em"}}>{label}</div>
        </div>
        {delta && (
          <span className="mono" style={{
            fontSize:11, padding:"4px 7px", borderRadius:6,
            background: delta.startsWith("-") ? "rgba(255,107,138,0.12)" : "rgba(0,224,164,0.12)",
            color: delta.startsWith("-") ? "#FF8FA5" : "#3EE8BE",
            border: `1px solid ${delta.startsWith("-") ? "rgba(255,107,138,0.25)" : "rgba(0,224,164,0.25)"}`
          }}>{delta}</span>
        )}
      </div>
      <div style={{fontSize:30,fontWeight:700,letterSpacing:"-0.03em",lineHeight:1, color:"var(--text)"}}>
        <AnimatedNum value={value} prefix={prefix} suffix={suffix} decimals={decimals}/>
      </div>
      {sub && <div style={{marginTop:8,fontSize:12,color:"var(--sub)"}}>{sub}</div>}
      {spark && <div style={{marginTop:14,opacity:.9}}>{spark}</div>}
    </div>
  );
}

// Product card image hover glow tracking
function useMouseGlow(){
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if(!el) return;
    const handle = (e) => {
      const r = el.getBoundingClientRect();
      el.style.setProperty("--mx", ((e.clientX - r.left)/r.width*100)+"%");
      el.style.setProperty("--my", ((e.clientY - r.top)/r.height*100)+"%");
    };
    el.addEventListener("mousemove", handle);
    return () => el.removeEventListener("mousemove", handle);
  }, []);
  return ref;
}

Object.assign(window, { ToastHost, showToast, CopyButton, AnimatedNum, Sparkline, CardArt, VideoThumb, Avatar, StatTile, useMouseGlow });
