// dream.jsx — 梦想口袋：5 槽位 + 拖拽自由排序 + 放飞动画 + 许愿面板（图片心愿）
const { useState, useRef, useEffect, useLayoutEffect } = React;

// 把底部弹层挂到 .phone 层，覆盖整个手机（含底部导航），避免被 app-body 裁切
function PhoneSheet({ children }) {
  const host = typeof document !== 'undefined' ? document.querySelector('.phone') : null;
  return host ? ReactDOM.createPortal(children, host) : children;
}

// 图片压缩：长边限制（默认 1000px，等比例只缩不放）+ JPEG 质量，转 base64 dataURL（控制入库体积）
function compressImage(file, maxEdge = 1000, quality = 0.7) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const img = new Image();
      img.onload = () => {
        let w = img.width, h = img.height;
        const scale = Math.min(1, maxEdge / Math.max(w, h));
        w = Math.round(w * scale); h = Math.round(h * scale);
        const canvas = document.createElement('canvas');
        canvas.width = w; canvas.height = h;
        canvas.getContext('2d').drawImage(img, 0, 0, w, h);
        try { resolve(canvas.toDataURL('image/jpeg', quality)); }
        catch (e) { reject(e); }
      };
      img.onerror = reject;
      img.src = reader.result;
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

// ---------- 一级：大图心愿卡（照片为主，点开看详情） ----------
function WishCard({ wish, justAdded, flying, dragging, cardRef, onOpen, onPointerDown }) {
  const tier = TIERS[wish.tier] || TIERS.small;
  return (
    <div ref={cardRef}
      className={'dp-card2' + (justAdded ? ' popin' : '') + (flying ? ' flying' : '') + (dragging ? ' dragging' : '')}
      style={{ '--tier': tier.color }}
      onPointerDown={(e) => onPointerDown(e, wish.id)}
      onClick={() => onOpen(wish)}>
      <div className="dp-card2-photo"
        style={wish.image ? undefined : { background: `linear-gradient(160deg, ${tier.color}33, ${tier.color}11)` }}>
        {wish.image
          ? <img src={wish.image} alt="" draggable="false" />
          : <span className="dp-card2-ph">{tier.emoji}</span>}
      </div>
      <div className="dp-card2-name">
        <span className="dp-card2-title">{wish.title}</span>
        <span className="dp-card2-sub" style={{ color: tier.color }}>{tier.emoji} {tier.label}</span>
      </div>
    </div>
  );
}

// ---------- 二级：心愿详情（底部弹层，可编辑「为什么想要」，放飞只在这里） ----------
function WishDetail({ wish, onClose, onAskRelease, onUpdate }) {
  const tier = TIERS[wish.tier] || TIERS.small;
  const kept = wishDaysKept(wish);
  const progress = Math.min(1, kept / tier.wait);
  const ready = kept >= tier.wait;
  const [note, setNote] = useState(wish.note || '');
  const [image, setImage] = useState(wish.image || '');
  const [busyImg, setBusyImg] = useState(false);
  const fileRef = useRef(null);

  const saveNote = () => {
    const v = note.trim();
    if (v !== (wish.note || '')) onUpdate(wish.id, { note: v });
  };
  const handleClose = () => { saveNote(); onClose(); };

  const pickImage = async (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = '';
    if (!file) return;
    setBusyImg(true);
    try {
      const data = await compressImage(file);
      setImage(data);
      onUpdate(wish.id, { image: data }); // 立即落库
    } catch (err) {}
    setBusyImg(false);
  };

  return (
    <div className="dp-sheet-back" onClick={handleClose}>
      <div className="dp-sheet dp-detail" style={{ '--tier': tier.color }} onClick={(e) => e.stopPropagation()}>
        <div className="dp-handle" />
        <button className={'dp-detail-photo' + (image ? ' has' : '')}
          onClick={() => fileRef.current && fileRef.current.click()}>
          {image ? <img src={image} alt="" /> : <span>{tier.emoji}</span>}
          <span className="dp-detail-photo-edit">{busyImg ? '处理中…' : (image ? '换张照片' : '＋ 加张照片')}</span>
        </button>
        <input ref={fileRef} type="file" accept="image/*"
          style={{ display: 'none' }} onChange={pickImage} />
        <div className="dp-detail-title">{wish.title}</div>
        <div className="dp-detail-meta">
          <span className="tg" style={{ color: tier.color }}>{tier.emoji} {tier.label}</span>
          <span className="dp-dot">·</span>
          <span>已陪伴 {kept} 天</span>
        </div>
        <div className="dp-bar">
          <div className="dp-bar-fill" style={{ width: (progress * 100) + '%', background: tier.color }} />
        </div>
        <div className="dp-bar-foot">
          {ready
            ? <span className="dp-ready">✨ 等待完成啦，可以和爸爸妈妈聊聊它</span>
            : <span>{tier.waitLabel} · 再等等就长大啦</span>}
        </div>

        <div className="dp-detail-label">💬 为什么想要它呢？</div>
        <textarea className="dp-detail-note-input" rows={2} placeholder="说说看…（可不填）"
          value={note} maxLength={60} onChange={(e) => setNote(e.target.value)} onBlur={saveNote} />

        <button className="dp-detail-release" onClick={() => onAskRelease(wish)}>
          <IconBalloon size={18} /> 放飞这个梦想
        </button>
      </div>
    </div>
  );
}

// ---------- 空槽位 ----------
function EmptySlot({ canAfford, onTap }) {
  return (
    <button className={'dp-slot-empty' + (canAfford ? '' : ' broke')} onClick={onTap}>
      {canAfford ? (
        <>
          <span className="dp-slot-plus">+</span>
          <span className="dp-slot-text">许个愿</span>
          <span className="dp-slot-cost"><Coin size={15} /> 1</span>
        </>
      ) : (
        <span className="dp-slot-text">金币不够啦，先攒一攒 🪙</span>
      )}
    </button>
  );
}

// ---------- 许愿面板（底部弹出） ----------
function AddWishSheet({ balance, onClose, onConfirm }) {
  const [title, setTitle] = useState('');
  const [tier, setTier] = useState('small');
  const [image, setImage] = useState('');
  const [busyImg, setBusyImg] = useState(false);
  const [saving, setSaving] = useState(false);
  const fileRef = useRef(null);
  const broke = balance < WISH_COST;
  const canSave = title.trim().length > 0 && !broke && !saving;

  const pickImage = async (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = ''; // 允许重复选同一张
    if (!file) return;
    setBusyImg(true);
    try { setImage(await compressImage(file)); } catch (err) {}
    setBusyImg(false);
  };

  const confirm = async () => {
    if (!canSave) return;
    setSaving(true);
    await onConfirm({ title: title.trim(), tier, image });
    // onConfirm 会关闭面板；失败时解除 saving 以便重试
    setSaving(false);
  };

  return (
    <div className="dp-sheet-back" onClick={onClose}>
      <div className="dp-sheet" onClick={(e) => e.stopPropagation()}>
        <div className="dp-handle" />
        <div className="dp-sheet-head">
          <Penguin size={46} mood="happy" />
          <div className="dp-sheet-head-txt">
            <div className="dp-sheet-title">许个愿 🌟</div>
            <div className="dp-sheet-sub">拍张照片，我陪你一起等它长大</div>
          </div>
          <button className={'dp-confirm-ic' + (canSave ? '' : ' disabled')} disabled={!canSave}
            onClick={confirm} aria-label="许下这个愿（花 1 金币）">
            {saving ? <span className="dp-ic-dots">···</span> : <IconCheck size={24} />}
          </button>
        </div>

        {/* 心愿图片：拍照 / 相册 */}
        <button className={'dp-photo' + (image ? ' has' : '')} onClick={() => fileRef.current && fileRef.current.click()}>
          {image
            ? <img className="dp-photo-img" src={image} alt="心愿图片" />
            : (busyImg
                ? <span className="dp-photo-hint">正在处理图片…</span>
                : <span className="dp-photo-hint"><span className="dp-photo-ic">📷</span>拍张照片 / 选张图片<br /><small>想要的玩具、画作都可以</small></span>)}
          {image && <span className="dp-photo-edit">换一张</span>}
        </button>
        <input ref={fileRef} type="file" accept="image/*"
          style={{ display: 'none' }} onChange={pickImage} />

        <input className="dp-input" placeholder="我想要…（例如：乐高消防车）"
          value={title} maxLength={18} onChange={(e) => setTitle(e.target.value)} />

        <div className="dp-tier-label">这是多大的梦想呀？</div>
        <div className="dp-tier-grid">
          {TIER_ORDER.map((id) => {
            const t = TIERS[id];
            return (
              <button key={id} className={'dp-tier-cell' + (tier === id ? ' on' : '')}
                style={{ '--tier': t.color }} onClick={() => setTier(id)}>
                <span className="dp-tier-emoji">{t.emoji}</span>
                <span className="dp-tier-name">{t.label}</span>
                <span className="dp-tier-meta">
                  <span className="dp-tier-wait">{t.waitLabel}</span>
                  <span className="dp-tier-range">{t.range}</span>
                </span>
              </button>
            );
          })}
        </div>

        {broke ? (
          <div className="dp-broke-hint"><Penguin size={30} mood="think" /> 金币不够啦，先去攒几枚金币吧～</div>
        ) : (
          <div className="dp-cost-hint">点右上角 ✓ 许下这个愿，要用掉 <Coin size={15} /> 1 枚金币</div>
        )}
      </div>
    </div>
  );
}

// ---------- 放飞确认 ----------
function ReleaseConfirm({ wish, onCancel, onConfirm }) {
  return (
    <div className="dp-sheet-back center" onClick={onCancel}>
      <div className="dp-confirm-modal" onClick={(e) => e.stopPropagation()}>
        <Penguin size={64} mood="think" />
        <div className="dp-confirm-title">让「{wish.title}」飞走吗？</div>
        <div className="dp-confirm-text">
          它会变成一只气球，飘向天空和你说再见。<br />
          飞走以后就找不回来啦，确定吗？
        </div>
        <div className="dp-confirm-btns">
          <button className="dp-btn-ghost" onClick={onCancel}>我再想想</button>
          <button className="dp-btn-fly" onClick={() => onConfirm(wish)}>让它飞走 🎈</button>
        </div>
      </div>
    </div>
  );
}

// ---------- 主屏 ----------
const DP_GAP = 18;
function DreamScreen({ wishes, balance, onAddWish, onReleaseWish, onReorder, onUpdateWish }) {
  const [sheet, setSheet] = useState(false);
  const [detail, setDetail] = useState(null);   // 正在查看详情的心愿（二级）
  const [releaseTarget, setReleaseTarget] = useState(null);
  const [flyingId, setFlyingId] = useState(null);
  const [justAdded, setJustAdded] = useState(null);
  const [items, setItems] = useState(() => activeWishes(wishes));
  const [dragId, setDragId] = useState(null);
  const listRef = useRef(null);
  const cardEls = useRef({});
  const drag = useRef(null);
  const clickSuppress = useRef(false); // 拖拽后抑制紧随的 click，避免误开详情
  const releaseFlip = useRef(null);    // 放飞后让其余卡片平滑补位（FLIP）

  // 与外部状态同步（拖拽时不打断）
  useEffect(() => {
    if (drag.current) return;
    setItems(activeWishes(wishes));
  }, [wishes]);

  // 放飞补位过渡：用放飞前记录的位置，让其余卡片从旧位置滑到新位置
  useLayoutEffect(() => {
    const flip = releaseFlip.current;
    if (!flip) return;
    releaseFlip.current = null;
    items.forEach((w) => {
      const el = cardEls.current[w.id];
      const oldTop = flip[w.id];
      if (!el || oldTop == null) return;
      const dy = oldTop - el.getBoundingClientRect().top;
      if (!dy) return;
      el.style.transition = 'none';
      el.style.transform = `translateY(${dy}px)`;
      requestAnimationFrame(() => {
        el.style.transition = 'transform .34s cubic-bezier(.2,.8,.3,1)';
        el.style.transform = '';
      });
      setTimeout(() => { el.style.transition = ''; el.style.transform = ''; }, 380);
    });
  }, [items]);

  const emptyCount = Math.max(0, MAX_SLOTS - items.length);
  const canAfford = balance >= WISH_COST;

  const confirmAdd = async (data) => {
    const res = await onAddWish(data);
    if (res && res.ok && res.wish) {
      setSheet(false);
      setJustAdded(res.wish.id);
      setTimeout(() => setJustAdded(null), 800);
    }
    // 失败（金币不足/槽位满）：保持面板开着，由面板内提示
  };

  const openDetail = (wish) => {
    if (clickSuppress.current) { clickSuppress.current = false; return; } // 刚拖拽过，不当作点击
    setDetail(wish);
  };

  // 二级里点「放飞」：先关详情，再弹放飞确认
  const askReleaseFromDetail = (wish) => {
    setDetail(null);
    setReleaseTarget(wish);
  };

  const doRelease = (wish) => {
    setReleaseTarget(null);
    setFlyingId(wish.id);
    setTimeout(() => {
      // 记录其余卡片当前位置，供移除后 FLIP 平滑补位
      const rects = {};
      items.forEach((w) => {
        if (w.id === wish.id) return;
        const el = cardEls.current[w.id];
        if (el) rects[w.id] = el.getBoundingClientRect().top;
      });
      releaseFlip.current = rects;
      onReleaseWish(wish.id);
      setFlyingId(null);
    }, 650);
  };

  // ---------- 拖拽排序 ----------
  const onPointerDown = (e, id) => {
    if (e.button != null && e.button !== 0) return;
    clickSuppress.current = false;
    const idx = items.findIndex((w) => w.id === id);
    if (idx < 0) return;
    const ref = cardEls.current[id];
    const scale = (ref.getBoundingClientRect().height / ref.offsetHeight) || 1;
    const layout = items.map((w) => {
      const r = cardEls.current[w.id].getBoundingClientRect();
      return { center: r.top + r.height / 2 };
    });
    drag.current = { id, idx, startY: e.clientY, layout, scale, draggedH: ref.offsetHeight, target: idx, started: false, pid: e.pointerId };
    try { e.currentTarget.setPointerCapture(e.pointerId); } catch (err) {}
  };

  const applyShift = (d) => {
    const sh = d.draggedH + DP_GAP;
    items.forEach((w, j) => {
      if (w.id === d.id) return;
      const el = cardEls.current[w.id];
      if (!el) return;
      el.style.transition = 'transform .18s ease';
      let ty = 0;
      if (d.target > d.idx && j > d.idx && j <= d.target) ty = -sh;
      else if (d.target < d.idx && j >= d.target && j < d.idx) ty = sh;
      el.style.transform = ty ? `translateY(${ty}px)` : '';
    });
  };

  const onPointerMove = (e) => {
    const d = drag.current;
    if (!d) return;
    const dy = e.clientY - d.startY;
    if (!d.started) {
      if (Math.abs(dy) < 5) return;
      d.started = true;
      clickSuppress.current = true; // 进入拖拽，抑制随后的 click
      setDragId(d.id);
    }
    e.preventDefault();
    const dEl = cardEls.current[d.id];
    dEl.style.transition = 'none';
    dEl.style.transform = `translateY(${dy / d.scale}px) scale(1.04)`;
    dEl.style.zIndex = '40';
    const center = d.layout[d.idx].center + dy;
    let count = 0;
    for (let j = 0; j < d.layout.length; j++) {
      if (j === d.idx) continue;
      if (d.layout[j].center < center) count++;
    }
    if (count !== d.target) { d.target = count; applyShift(d); }
  };

  const endDrag = () => {
    const d = drag.current;
    if (!d) return;
    drag.current = null;
    setDragId(null);
    items.forEach((w) => {
      const el = cardEls.current[w.id];
      if (el) { el.style.transition = ''; el.style.transform = ''; el.style.zIndex = ''; }
    });
    if (d.started && d.target !== d.idx) {
      const next = items.slice();
      const [m] = next.splice(d.idx, 1);
      next.splice(d.target, 0, m);
      setItems(next);
      onReorder(next.map((w) => w.id));
    }
  };

  return (
    <div className="screen dream">
      <div className="dp-head">
        <div>
          <div className="dp-h-title">梦想口袋</div>
        </div>
        <div className="dp-slots-badge">
          <IconDream size={16} />
          <b>{items.length}</b> / {MAX_SLOTS}
        </div>
      </div>

      <div className="dp-list" ref={listRef}
        onPointerMove={onPointerMove} onPointerUp={endDrag} onPointerCancel={endDrag}>
        {items.map((w) => (
          <WishCard key={w.id} wish={w}
            cardRef={(el) => { cardEls.current[w.id] = el; }}
            justAdded={justAdded === w.id}
            flying={flyingId === w.id}
            dragging={dragId === w.id}
            onOpen={openDetail}
            onPointerDown={onPointerDown} />
        ))}
        {Array.from({ length: emptyCount }).map((_, i) => (
          <EmptySlot key={'e' + i} canAfford={canAfford} onTap={() => setSheet(true)} />
        ))}
      </div>

      {items.length === MAX_SLOTS && (
        <div className="dp-full-hint">
          <Penguin size={34} mood="happy" /> 口袋满满的！想要新梦想，先放飞一个吧～
        </div>
      )}

      {detail && <PhoneSheet><WishDetail wish={detail} onClose={() => setDetail(null)} onAskRelease={askReleaseFromDetail} onUpdate={onUpdateWish} /></PhoneSheet>}
      {sheet && <PhoneSheet><AddWishSheet balance={balance} onClose={() => setSheet(false)} onConfirm={confirmAdd} /></PhoneSheet>}
      {releaseTarget && <PhoneSheet><ReleaseConfirm wish={releaseTarget} onCancel={() => setReleaseTarget(null)} onConfirm={doRelease} /></PhoneSheet>}
    </div>
  );
}
window.DreamScreen = DreamScreen;
