/* 织遗录 · 龙身画布 DragonCanvas —— 写实版(HTML/CSS,稳定可渲染)
   真实那条龙(宝小格 × 变废厂,黄龙溪旧物结成)作底图;龙身上铺满由真实旧布裁出的
   鳞片,会不断长长。龙头保留照片本身,龙身是众人共写的拼布。
   - scales: 最新的真实鳞片(数组靠前=靠近龙头,带 text/cloth/author/place)
   - total:  连同环境鳞片在内最多铺多少片(0=按图自适应)
   - ceremony: 触发火花迸发(鳞片缝上时的正反馈)
   - onScaleClick(scale): 点开一片鳞读那句话
   导出 window.WL.DragonCanvas */
(function () {
  const IMG = "assets/dragon/dragon-2k.png";
  const FAB = (n) => "assets/fabric/fabric" + n + ".jpg";
  const VW = 1700, VH = 771;
  const SPARK_HEX = ["#9e3b2a", "#c9a44a", "#5b6f57", "#7a8aa0", "#9c7a3c"];

  function hash2(s) {
    s = "" + s; let h = 2166136261;
    for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); }
    const a = ((h >>> 0) % 1e5) / 1e5;
    h = Math.imul(h ^ 0x9e3779b9, 16777619);
    return [a, ((h >>> 0) % 1e5) / 1e5];
  }

  function DragonCanvas({ scales = [], total = 0, ceremony = false, onScaleClick, height = 420, still = false }) {
    const [slots, setSlots] = React.useState(null);

    // 载入龙图 → 采样不透明像素 → 在龙身(跳过龙头区)铺鳞位(归一化 0–1)
    React.useEffect(() => {
      let cancelled = false;
      const im = new Image();
      im.crossOrigin = "anonymous";
      im.onload = () => {
        if (cancelled) return;
        const SP = 0.0265 * VW, rh = SP * 0.86, er = Math.max(2, (SP * 0.16) | 0);
        const oc = document.createElement("canvas");
        oc.width = VW; oc.height = VH;
        const cx = oc.getContext("2d");
        cx.drawImage(im, 0, 0, VW, VH);
        let data;
        try { data = cx.getImageData(0, 0, VW, VH).data; }
        catch (e) { return setSlots(fallback()); }
        const opaque = (px, py) => {
          px |= 0; py |= 0;
          if (px < 0 || py < 0 || px >= VW || py >= VH) return false;
          return data[(py * VW + px) * 4 + 3] > 90;
        };
        const inside = (px, py) =>
          opaque(px, py) && opaque(px - er, py) && opaque(px + er, py) && opaque(px, py - er) && opaque(px, py + er);
        const out = [];
        let row = 0;
        for (let y = rh; y < VH - rh; y += rh) {
          const xoff = (row % 2) ? SP / 2 : 0;
          for (let px = xoff; px < VW; px += SP) {
            if (px > 0.27 * VW && inside(px, y)) out.push({ u: px / VW, v: y / VH });
          }
          row++;
        }
        out.sort((a, b) => a.u - b.u);
        setSlots(out.length ? out : fallback());
      };
      im.onerror = () => setSlots(fallback());
      im.src = IMG;
      return () => { cancelled = true; };
    }, []);

    function fallback() {
      const arr = [];
      for (let i = 0; i < 200; i++) {
        const t = i / 200;
        arr.push({ u: 0.30 + t * 0.66, v: 0.55 + Math.sin(t * 7) * 0.2 });
      }
      return arr;
    }

    const placed = React.useMemo(() => {
      if (!slots) return [];
      const n = total > 0 ? Math.min(total, slots.length) : slots.length;
      const arr = [];
      for (let i = 0; i < n; i++) {
        const real = scales[i] || null;
        const fabN = real
          ? (parseInt(String(real.cloth).replace(/\D/g, ""), 10) || 1)
          : ((i * 3 + 1) % 7) + 1;
        arr.push({ i, slot: slots[i], real, fabN, newest: i === 0 && !!real });
      }
      return arr;
    }, [slots, scales, total]);

    const anchor = slots && slots.length ? slots[Math.min(5, slots.length - 1)] : { u: 0.33, v: 0.5 };
    const scaleWpct = 4.7;       // 鳞宽 = 容器宽的 4.7%(更小更密,扇形层层叠压)

    return (
      <div className="wl-dragon-scroll"
        style={{ position: "relative", height, width: "100%", overflowX: "auto", overflowY: "hidden",
          background: "var(--surface-page)", borderRadius: "var(--radius-md)" }}>
        <div className={"wl-dragon-frame" + (still ? "" : " wl-sway")}
          style={{ position: "relative", height: "100%", minWidth: 720, aspectRatio: `${VW}/${VH}`, margin: "0 auto" }}>

          {/* 扇形鳞片裁切路径(objectBoundingBox,随尺寸自适应):尖头朝左、圆弧大头朝右 */}
          <svg width="0" height="0" style={{ position: "absolute" }} aria-hidden="true">
            <defs>
              <clipPath id="wlBodyFan" clipPathUnits="objectBoundingBox">
                <path d="M0.07,0.5 L0.66,0.1 Q1,0.5 0.66,0.9 Z" />
              </clipPath>
            </defs>
          </svg>

          {/* 底图:真实那条龙 */}
          <img src={IMG} alt="一条由黄龙溪旧物结成的龙" draggable="false"
            style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "contain", display: "block", userSelect: "none" }} />

          {/* 龙身鳞片(真实旧布裁切成叶形) */}
          {placed.map((p) => {
            const [hx] = hash2(p.real ? "s" + p.real.id : "n" + p.i);
            const deg = (hx * 16 - 8).toFixed(1);
            return (
              <button key={p.i}
                onClick={p.real ? (e) => { e.stopPropagation(); onScaleClick && onScaleClick(p.real); } : undefined}
                title={p.real ? "点开读这句话" : undefined}
                className={"wl-dscale" + (ceremony ? " wl-ceremony" : "") + (p.real ? " wl-real" : "")}
                style={{
                  position: "absolute", left: (p.slot.u * 100) + "%", top: (p.slot.v * 100) + "%",
                  width: scaleWpct + "%", aspectRatio: "1.25/1", padding: 0, border: "none",
                  transform: `translate(-50%,-50%) rotate(${deg}deg)`,
                  background: `url("${FAB(p.fabN)}") center/cover`,
                  clipPath: "url(#wlBodyFan)",
                  filter: p.newest
                    ? "drop-shadow(0 0 6px color-mix(in srgb,var(--brass-500) 75%,transparent))"
                    : "drop-shadow(1.5px 2px 1.5px rgba(28,24,19,.45))",
                  cursor: p.real ? "pointer" : "default",
                  ["--d"]: (p.i * 7) + "ms",
                  zIndex: p.newest ? 40 : 2 + Math.round((1 - p.slot.u) * 12),
                }} />
            );
          })}

          {/* 正反馈:火花迸发 + 中心强闪 */}
          {ceremony && (
            <div style={{ position: "absolute", left: (anchor.u * 100) + "%", top: (anchor.v * 100) + "%", zIndex: 6, pointerEvents: "none" }}>
              <span className="wl-flash" />
              {Array.from({ length: 22 }).map((_, k) => {
                const a = (k / 22) * Math.PI * 2, d = 70 + (k % 5) * 26;
                return <span key={k} className="wl-spark" style={{
                  background: SPARK_HEX[k % 5],
                  ["--ex"]: (Math.cos(a) * d).toFixed(0) + "px",
                  ["--ey"]: (Math.sin(a) * d - 18).toFixed(0) + "px",
                  ["--sd"]: (k * 13) + "ms",
                }} />;
              })}
            </div>
          )}
        </div>

        <style>{`
          .wl-dragon-scroll::-webkit-scrollbar{height:8px}
          .wl-dragon-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--ink-800) 22%,transparent);border-radius:999px}
          .wl-dscale{transition:filter .15s var(--ease-out), transform .15s var(--ease-out)}
          .wl-dscale.wl-real:hover{filter:brightness(1.12) drop-shadow(2px 3px 3px rgba(28,24,19,.5));z-index:50!important}
          .wl-flash{position:absolute;left:-90px;top:-90px;width:180px;height:180px;border-radius:50%;
            background:radial-gradient(circle,rgba(255,243,214,.95),rgba(201,164,74,.5) 36%,transparent 68%)}
          .wl-spark{position:absolute;left:-5px;top:-5px;width:10px;height:10px;border-radius:50%;box-shadow:0 0 7px rgba(201,164,74,.85)}
          @media (prefers-reduced-motion: no-preference){
            .wl-sway{animation:wlSway 9s var(--ease-inout) infinite}
            @keyframes wlSway{0%,100%{transform:translateY(0) rotate(-.3deg)}50%{transform:translateY(-7px) rotate(.3deg)}}
            .wl-ceremony.wl-real{animation:wlPop 1.1s var(--ease-out) both;animation-delay:var(--d)}
            @keyframes wlPop{0%{filter:brightness(1)}35%{filter:brightness(1.85) saturate(1.3)}100%{filter:brightness(1)}}
            .wl-flash{opacity:0;animation:wlFlash .8s var(--ease-out) both}
            @keyframes wlFlash{0%{opacity:0;transform:scale(.3)}25%{opacity:1}100%{opacity:0;transform:scale(2.2)}}
            .wl-spark{opacity:0;animation:wlSpark 1.05s var(--ease-out) both;animation-delay:var(--sd)}
            @keyframes wlSpark{0%{opacity:0;transform:translate(0,0) scale(.4)}18%{opacity:1}100%{opacity:0;transform:translate(var(--ex),var(--ey)) scale(.3)}}
          }
        `}</style>
      </div>
    );
  }

  window.WL = window.WL || {};
  window.WL.DragonCanvas = DragonCanvas;
})();
