/* 彩云间 — 水彩云朵插画系统
   一个 <CloudDefs/> 提供共享的水彩滤镜（晕染边缘 + 柔化），
   <CloudArt shape tone/> 用分层半透明色块画出不同云种，模拟水彩透叠质感。 */

let __cyUid = 0;
function useCloudUid() {
  const ref = React.useRef(null);
  if (ref.current === null) ref.current = 'cl' + (++__cyUid);
  return ref.current;
}

// 配色基调 ───────────────────────────────────────────────
const CLOUD_TONES = {
  white:  { base:'#d8e6f2', mid:'#e9f1fa', body:'#fbfdff', hi:'#ffffff', shadow:'#c7d9ec' },
  soft:   { base:'#c6d4e3', mid:'#d9e4f0', body:'#eef4fb', hi:'#fdfeff', shadow:'#b6c5d6' },
  ice:    { base:'#d9e7f4', mid:'#e7f1fb', body:'#f6fbff', hi:'#ffffff', shadow:'#caddf0' },
  storm:  { base:'#76828f', mid:'#95a2af', body:'#bcc8d3', hi:'#e9eef3', shadow:'#5e6a77' },
  rain:   { base:'#8c99a5', mid:'#a6b1bd', body:'#c6ced7', hi:'#e1e7ec', shadow:'#76828e' },
  sunset: { base:'#e26a45', mid:'#f0974f', body:'#f8c66f', hi:'#ffe6a0', shadow:'#cf5566' },
  night:  { base:'#27496e', mid:'#4d7da8', body:'#9bd8ef', hi:'#dff5ff', shadow:'#1a3050' },
  pearl:  { base:'#ddc0e2', mid:'#c4e0db', body:'#f4e6cf', hi:'#ffffff', shadow:'#cfb6e0' },
};

// 共享滤镜（整页只渲染一次）─────────────────────────────
function CloudDefs() {
  return (
    <svg width="0" height="0" style={{ position:'absolute' }} aria-hidden="true">
      <defs>
        <filter id="cy-wc" x="-25%" y="-25%" width="150%" height="150%">
          <feTurbulence type="fractalNoise" baseFrequency="0.013 0.02" numOctaves="2" seed="7" result="n"/>
          <feDisplacementMap in="SourceGraphic" in2="n" scale="13" xChannelSelector="R" yChannelSelector="G" result="d"/>
          <feGaussianBlur in="d" stdDeviation="1.2"/>
        </filter>
        <filter id="cy-wc-soft" x="-30%" y="-30%" width="160%" height="160%">
          <feTurbulence type="fractalNoise" baseFrequency="0.018 0.026" numOctaves="2" seed="3" result="n"/>
          <feDisplacementMap in="SourceGraphic" in2="n" scale="9" xChannelSelector="R" yChannelSelector="G" result="d"/>
          <feGaussianBlur in="d" stdDeviation="2"/>
        </filter>
        <filter id="cy-grain" x="0" y="0" width="100%" height="100%">
          <feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" result="g"/>
          <feColorMatrix in="g" type="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.5 0"/>
        </filter>
      </defs>
    </svg>
  );
}

// 一组“块状云”：阴影层 + 主体层 + 高光层 ────────────────
function Cumuliform({ lumps, T, uid, base = true }) {
  return (
    <g>
      {base && <ellipse cx="120" cy="124" rx="92" ry="18" fill={T.base} opacity="0.55" />}
      {/* 阴影 */}
      {lumps.map((l, i) => (
        <circle key={'s'+i} cx={l[0]} cy={l[1] + 7} r={l[2]} fill={T.shadow} opacity="0.85" />
      ))}
      {/* 主体 */}
      {lumps.map((l, i) => (
        <circle key={'b'+i} cx={l[0]} cy={l[1]} r={l[2]} fill={`url(#${uid}-g)`} />
      ))}
      {/* 高光 */}
      {lumps.map((l, i) => (
        l[2] > 18 ? <circle key={'h'+i} cx={l[0] - l[2]*0.28} cy={l[1] - l[2]*0.34} r={l[2]*0.46} fill={T.hi} opacity="0.6" /> : null
      ))}
    </g>
  );
}

function strokeWisp(d, T, w, op) {
  return <path d={d} fill="none" stroke={`url(#${'wstroke'}`} />;
}

// 各云种造型 ─────────────────────────────────────────────
function renderShape(shape, T, uid) {
  const g = `url(#${uid}-g)`;
  switch (shape) {
    case 'puff':
      return <Cumuliform uid={uid} T={T} lumps={[[64,112,22],[92,96,32],[124,86,40],[158,98,34],[186,110,22]]} />;
    case 'fragment':
      return <g opacity="0.96">
        <Cumuliform uid={uid} T={T} base={false} lumps={[[58,104,16],[86,112,12]]} />
        <Cumuliform uid={uid} T={T} base={false} lumps={[[126,92,22],[152,100,15],[174,94,12]]} />
      </g>;
    case 'tower':
      return <Cumuliform uid={uid} T={T} lumps={[[120,122,42],[104,92,30],[132,78,30],[116,50,24],[126,30,17]]} />;
    case 'anvil':
      return <g>
        <ellipse cx="120" cy="128" rx="96" ry="18" fill={T.base} opacity="0.6" />
        {/* 砧顶 */}
        <ellipse cx="118" cy="34" rx="104" ry="17" fill={T.shadow} opacity="0.7" />
        <ellipse cx="120" cy="30" rx="100" ry="14" fill={g} />
        <Cumuliform uid={uid} T={T} base={false} lumps={[[120,120,44],[100,90,32],[138,84,30],[120,58,26]]} />
      </g>;
    case 'cap':
      return <g>
        <Cumuliform uid={uid} T={T} base={false} lumps={[[120,124,40],[106,98,28],[134,92,26],[120,72,22]]} />
        <ellipse cx="120" cy="50" rx="58" ry="11" fill={T.hi} opacity="0.78" />
        <ellipse cx="120" cy="52" rx="58" ry="11" fill="none" stroke={T.shadow} strokeOpacity="0.3" strokeWidth="1.4" />
      </g>;
    case 'roll': {
      const row = (y, rx, ry, op) => Array.from({length:5}).map((_,i)=>(
        <ellipse key={y+'-'+i} cx={32+i*44} cy={y} rx={rx} ry={ry} fill={i%2? g : T.mid} opacity={op}/>
      ));
      return <g>
        <g opacity="0.85">{row(118,30,15,0.9)}</g>
        <g>{row(96,28,14,1)}</g>
        <g opacity="0.92">{row(76,24,12,0.95)}</g>
      </g>;
    }
    case 'sheet':
      return <g>
        <ellipse cx="120" cy="112" rx="116" ry="20" fill={T.shadow} opacity="0.5"/>
        <ellipse cx="120" cy="92" rx="120" ry="22" fill={T.mid} opacity="0.92"/>
        <ellipse cx="118" cy="74" rx="110" ry="18" fill={g} opacity="0.96"/>
        <ellipse cx="124" cy="60" rx="92" ry="13" fill={T.hi} opacity="0.5"/>
      </g>;
    case 'dapple': {
      const rows = [
        {y:62, n:9, r:6, sp:24, x:24},
        {y:84, n:8, r:8, sp:28, x:30},
        {y:108, n:7, r:10, sp:32, x:36},
      ];
      return <g>
        {rows.map((rw,ri)=>Array.from({length:rw.n}).map((_,i)=>(
          <g key={ri+'-'+i}>
            <circle cx={rw.x+i*rw.sp} cy={rw.y+5} r={rw.r} fill={T.shadow} opacity="0.6"/>
            <circle cx={rw.x+i*rw.sp} cy={rw.y} r={rw.r} fill={g}/>
          </g>
        )))}
      </g>;
    }
    case 'veil':
      return <g>
        <circle cx="120" cy="80" r="34" fill={T.hi} opacity="0.85"/>
        <circle cx="120" cy="80" r="50" fill={T.hi} opacity="0.3"/>
        <ellipse cx="120" cy="88" rx="120" ry="40" fill={T.mid} opacity="0.62"/>
        <ellipse cx="118" cy="74" rx="116" ry="30" fill={T.body} opacity="0.4"/>
      </g>;
    case 'halo':
      return <g>
        <circle cx="120" cy="78" r="42" fill="none" stroke={T.mid} strokeWidth="6" opacity="0.55"/>
        <circle cx="120" cy="78" r="42" fill="none" stroke={T.hi} strokeWidth="2" opacity="0.9"/>
        <circle cx="120" cy="78" r="20" fill={T.hi} opacity="0.9"/>
        <ellipse cx="120" cy="84" rx="118" ry="34" fill={T.mid} opacity="0.34"/>
      </g>;
    case 'wisp': {
      const W = ({d,w,o})=> <path d={d} fill="none" stroke={g} strokeWidth={w} strokeLinecap="round" opacity={o}/>;
      return <g>
        <W d="M26 96 Q92 60 150 56 T214 44" w="9" o="0.9"/>
        <W d="M40 116 Q104 86 168 80 T222 72" w="7" o="0.8"/>
        <W d="M22 70 Q70 50 120 50" w="5" o="0.7"/>
        <W d="M70 124 Q120 104 180 104" w="5" o="0.65"/>
        <path d="M150 56 q14 -6 30 -3" stroke={T.hi} strokeWidth="3" fill="none" strokeLinecap="round" opacity="0.7"/>
      </g>;
    }
    case 'hook': {
      const H = ({x,y})=> <g>
        <path d={`M${x} ${y} q40 -4 70 -2`} fill="none" stroke={g} strokeWidth="7" strokeLinecap="round"/>
        <path d={`M${x} ${y} q-12 2 -16 16 q-2 10 8 12`} fill="none" stroke={g} strokeWidth="8" strokeLinecap="round"/>
      </g>;
      return <g opacity="0.92"><H x={56} y={70}/><H x={120} y={94}/><H x={92} y={118}/></g>;
    }
    case 'lens':
      return <g>
        <ellipse cx="120" cy="104" rx="96" ry="16" fill={T.shadow} opacity="0.7"/>
        <ellipse cx="120" cy="96" rx="100" ry="20" fill={g}/>
        <ellipse cx="120" cy="80" rx="74" ry="15" fill={T.body} opacity="0.95"/>
        <ellipse cx="120" cy="68" rx="44" ry="10" fill={T.hi} opacity="0.85"/>
        <ellipse cx="106" cy="90" rx="40" ry="6" fill={T.hi} opacity="0.5"/>
      </g>;
    case 'bubbles': {
      const xs = [40,72,104,136,168,200];
      return <g>
        <ellipse cx="120" cy="56" rx="116" ry="22" fill={T.mid} opacity="0.92"/>
        <ellipse cx="118" cy="48" rx="112" ry="16" fill={g} opacity="0.9"/>
        {xs.map((x,i)=>(
          <g key={i}>
            <ellipse cx={x} cy={82} rx={17} ry={20} fill={T.shadow} opacity="0.85"/>
            <ellipse cx={x} cy={78} rx={15} ry={18} fill={g}/>
            <ellipse cx={x-4} cy={72} rx={6} ry={7} fill={T.hi} opacity="0.5"/>
          </g>
        ))}
      </g>;
    }
    case 'wave': {
      const wave = (y, amp, o, fill)=> {
        let d = `M-8 ${y}`;
        for (let x=0; x<=248; x+=31) d += ` q15 ${-amp} 31 0 t31 0`;
        d += ` L248 150 L-8 150 Z`;
        return <path d={d} fill={fill} opacity={o}/>;
      };
      return <g>
        {wave(112, 16, 0.55, T.shadow)}
        {wave(96, 22, 0.9, T.mid)}
        {wave(82, 18, 0.95, g)}
        {wave(70, 12, 0.5, T.hi)}
      </g>;
    }
    case 'curl': {
      const C = ({x,y})=> <path d={`M${x} ${y} q22 -2 26 -22 q2 -14 -12 -14 q-10 0 -8 12 q2 9 14 7`}
        fill="none" stroke={g} strokeWidth="9" strokeLinecap="round" strokeLinejoin="round"/>;
      return <g>
        <line x1="8" y1="100" x2="232" y2="100" stroke={T.shadow} strokeWidth="6" opacity="0.4" strokeLinecap="round"/>
        {[28,84,140,196].map((x,i)=><C key={i} x={x} y={100}/>)}
      </g>;
    }
    case 'shelf':
      return <g>
        <path d="M-6 150 L-6 96 Q60 70 120 78 Q186 86 246 64 L246 150 Z" fill={T.shadow} opacity="0.75"/>
        <path d="M-6 150 L-6 104 Q60 82 120 90 Q186 98 246 78 L246 150 Z" fill={g}/>
        <path d="M-6 108 Q60 88 120 96 Q186 104 246 86" fill="none" stroke={T.hi} strokeWidth="4" opacity="0.5"/>
      </g>;
    case 'iris': {
      const band = (y, rx, fill, o)=> <ellipse cx="120" cy={y} rx={rx} ry="13" fill={fill} opacity={o}/>;
      return <g>
        {band(98, 116, T.base, 0.4)}
        {band(86, 108, '#f6c9d8', 0.5)}
        {band(76, 96, '#cfe7df', 0.5)}
        {band(66, 80, '#f4e6c4', 0.55)}
        {band(58, 60, T.hi, 0.7)}
      </g>;
    }
    case 'sunset': {
      const band = (y, rx, ry, fill, o)=> <ellipse cx="120" cy={y} rx={rx} ry={ry} fill={fill} opacity={o}/>;
      return <g>
        <circle cx="120" cy="92" r="40" fill={T.hi} opacity="0.55"/>
        {band(116, 122, 12, T.base, 0.9)}
        {band(100, 112, 14, T.mid, 0.95)}
        {band(82, 92, 12, g, 0.95)}
        {band(66, 64, 9, T.hi, 0.9)}
        {band(108, 70, 7, T.hi, 0.55)}
      </g>;
    }
    case 'contrail':
      return <g>
        <path d="M18 132 L210 36" stroke={T.shadow} strokeWidth="11" strokeLinecap="round" opacity="0.4"/>
        <path d="M18 132 L210 36" stroke={g} strokeWidth="7" strokeLinecap="round"/>
        <path d="M18 132 L210 36" stroke={T.hi} strokeWidth="2.5" strokeLinecap="round" opacity="0.8"/>
        <g transform="translate(210 36) rotate(-27)">
          <ellipse cx="0" cy="0" rx="11" ry="4" fill={T.shadow}/>
          <path d="M-1 -1 l-10 -8 l2 9 Z" fill={T.shadow}/>
          <path d="M-1 1 l-10 8 l2 -9 Z" fill={T.shadow}/>
        </g>
      </g>;
    case 'tube':
      return <g>
        <rect x="-10" y="86" width="260" height="40" rx="20" fill={T.shadow} opacity="0.7"/>
        <rect x="-10" y="78" width="260" height="38" rx="19" fill={g}/>
        <rect x="-10" y="76" width="260" height="14" rx="7" fill={T.hi} opacity="0.6"/>
        <ellipse cx="36" cy="97" rx="14" ry="19" fill={T.body}/>
      </g>;
    default:
      return <Cumuliform uid={uid} T={T} lumps={[[92,96,32],[124,86,40],[158,98,30]]} />;
  }
}

function CloudArt({ shape = 'puff', tone = 'white', style = {}, soft = false }) {
  const uid = useCloudUid();
  const T = CLOUD_TONES[tone] || CLOUD_TONES.white;
  return (
    <svg viewBox="0 0 240 160" preserveAspectRatio="xMidYMid meet" style={style} aria-hidden="true">
      <defs>
        <radialGradient id={`${uid}-g`} cx="42%" cy="34%" r="78%">
          <stop offset="0%" stopColor={T.hi} />
          <stop offset="52%" stopColor={T.body} />
          <stop offset="100%" stopColor={T.mid} />
        </radialGradient>
      </defs>
      <g filter={soft ? 'url(#cy-wc-soft)' : 'url(#cy-wc)'}>
        {renderShape(shape, T, uid)}
      </g>
    </svg>
  );
}

Object.assign(window, { CloudDefs, CloudArt, CLOUD_TONES });
