/* board.jsx — Card, Column, Board with pointer drag-and-drop. Exported to window. */

function Tag({ kind, value }) {
  const { Ic, Store } = window;
  const meta = kind === "cat" ? Store.CATEGORIES[value] : Store.PRIORITIES[value];
  if (!meta) return null;
  const I = meta.icon ? Ic[meta.icon] : null;
  return (
    <span className="tag" style={{ color: meta.color, background: meta.bg }}>
      {I && <I size={12} />}{meta.label}
    </span>
  );
}

function CardCover({ images, art, isStatic, onOpenImages }) {
  const { Ic, FX } = window;
  const stripRef = React.useRef(null);
  const [edge, setEdge] = React.useState({ left: false, right: false });
  const realPhotos = images && images.length > 0;
  const list = realPhotos ? images : (art ? [art] : []);
  const stop = (e) => e.stopPropagation();
  const openFull = (i, e) => { if (isStatic || !onOpenImages) return; if (e) e.stopPropagation(); FX.sfx.play("click"); onOpenImages(i); };

  const upd = () => {
    const el = stripRef.current; if (!el) return;
    setEdge({ left: el.scrollLeft > 4, right: el.scrollLeft + el.clientWidth < el.scrollWidth - 4 });
  };
  React.useEffect(() => { const t = setTimeout(upd, 60); return () => clearTimeout(t); }, [list.length]);

  if (!list.length) return null;

  // single photo or themed art → one full cover (complete image, blurred fill)
  if (!realPhotos || list.length === 1) {
    return (
      <div className={"card-thumb" + (realPhotos ? " ct-photo" : "") + (realPhotos && !isStatic ? " zoomable" : "")}>
        {realPhotos && <div className="ct-blur" style={{ backgroundImage: `url("${list[0]}")` }} />}
        <img className="card-thumb-img" src={list[0]} alt="" draggable="false"
          onPointerDown={realPhotos && !isStatic ? stop : undefined} onClick={(e) => openFull(0, e)} />
      </div>
    );
  }

  // multiple photos → responsive horizontal thumbnail strip
  const scroll = (d, e) => {
    e.stopPropagation(); const el = stripRef.current; if (!el) return;
    el.scrollBy({ left: d * el.clientWidth * 0.8, behavior: "smooth" });
    setTimeout(upd, 320);
  };
  return (
    <div className="cc-wrap">
      <div className="cc-strip" ref={stripRef} onScroll={upd} onPointerDown={isStatic ? undefined : stop}>
        {list.map((u, i) => (
          <button key={i} className="cc-shot" onPointerDown={stop} onClick={(e) => openFull(i, e)}
            aria-label={"Ver imagem " + (i + 1)}>
            <div className="cc-shot-blur" style={{ backgroundImage: `url("${u}")` }} />
            <img src={u} alt="" draggable="false" />
          </button>
        ))}
      </div>
      <div className="cc-badge">{list.length} fotos</div>
      {!isStatic && edge.left && (
        <button className="cc-arrow left" onPointerDown={stop} onClick={(e) => scroll(-1, e)} aria-label="Voltar">
          <Ic.Chevron size={18} style={{ transform: "rotate(90deg)" }} />
        </button>
      )}
      {!isStatic && edge.right && (
        <button className="cc-arrow right" onPointerDown={stop} onClick={(e) => scroll(1, e)} aria-label="Avançar">
          <Ic.Chevron size={18} style={{ transform: "rotate(-90deg)" }} />
        </button>
      )}
    </div>
  );
}


function ProgressBar({ pct }) {
  const full = pct >= 100;
  return (
    <div className="prog-row">
      <div className="prog-track">
        <div className={"prog-fill" + (full ? " full" : "")} style={{ width: pct + "%" }} />
      </div>
      <span className={"prog-pct" + (full ? " full" : "")}>{pct}%</span>
    </div>
  );
}

const Card = React.forwardRef(function Card(
  { task, pct, onPointerDown, onOpenImages, selected, popping, isStatic }, ref) {
  const { Ic, FX } = window;
  return (
    <div ref={ref} data-card={task.id}
      className={"card" + (selected ? " selected" : "") + (popping ? " pop" : "")}
      onPointerDown={isStatic ? undefined : onPointerDown}
      role={isStatic ? undefined : "button"} tabIndex={isStatic ? undefined : 0}
      onKeyDown={isStatic ? undefined : (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onPointerDown && onPointerDown({ _kbd: true, currentTarget: e.currentTarget }); } }}>
      <div className="card-title">{task.title}</div>
      <div className="tags">
        <Tag kind="cat" value={task.category} />
        {task.priority === "alta" && <Tag kind="prio" value={task.priority} />}
      </div>
      <ProgressBar pct={pct} />
      <CardCover images={task.images} art={task.thumb ? FX.thumbDataUrl(task.thumb) : null}
        isStatic={isStatic} onOpenImages={onOpenImages ? (i) => onOpenImages(task, i) : null} />
    </div>
  );
});

function Congrats() {
  const { Ic } = window;
  return (
    <div className="congrats">
      <div className="congrats-ring"><Ic.Trophy size={56} /></div>
      <h2>Tudo limpo!</h2>
      <p>Você zerou a coluna "A Fazer". Aproveite a vitória — ou crie a próxima missão.</p>
    </div>
  );
}

function Board({ tasks, query, catFilter, prioFilter, onOpen, onOpenImages, onMove, onAdd, selectedId, popId }) {
  const { Store, FX } = window;
  const [drag, setDrag] = React.useState(null);
  const dragRef = React.useRef(null);
  const colBodies = React.useRef({});
  const bumpRef = React.useRef({});
  const [bumps, setBumps] = React.useState({});

  // filtered + grouped
  const filtered = React.useMemo(() => {
    const q = query.trim().toLowerCase();
    return tasks.filter(t => {
      if (q && !(t.title.toLowerCase().includes(q) || t.desc.toLowerCase().includes(q))) return false;
      if (catFilter && t.category !== catFilter) return false;
      if (prioFilter && t.priority !== prioFilter) return false;
      return true;
    });
  }, [tasks, query, catFilter, prioFilter]);

  const byCol = React.useMemo(() => {
    const m = { todo: [], doing: [], done: [] };
    filtered.forEach(t => m[t.status].push(t));
    return m;
  }, [filtered]);

  // true counts (unfiltered) for headers
  const counts = React.useMemo(() => {
    const m = { todo: 0, doing: 0, done: 0 };
    tasks.forEach(t => m[t.status]++); return m;
  }, [tasks]);

  // animate count bump when a column count changes
  const prevCounts = React.useRef(counts);
  React.useEffect(() => {
    Store.COLUMNS.forEach(c => {
      if (prevCounts.current[c.id] !== undefined && counts[c.id] > prevCounts.current[c.id]) {
        setBumps(b => ({ ...b, [c.id]: (b[c.id] || 0) + 1 }));
        setTimeout(() => setBumps(b => ({ ...b, [c.id]: 0 })), 420);
      }
    });
    prevCounts.current = counts;
  }, [counts]);

  const filterActive = query.trim() || catFilter || prioFilter;

  /* ---- drag computation ---- */
  const computeDrop = (px, py, dragId) => {
    let col = null;
    for (const c of Store.COLUMNS) {
      const el = colBodies.current[c.id];
      if (!el) continue;
      const r = el.getBoundingClientRect();
      if (px >= r.left && px <= r.right) { col = c.id; break; }
    }
    if (!col) {
      // nearest by x center
      let best = null, bestD = 1e9;
      for (const c of Store.COLUMNS) {
        const el = colBodies.current[c.id]; if (!el) continue;
        const r = el.getBoundingClientRect(); const cx = (r.left + r.right) / 2;
        const d = Math.abs(px - cx); if (d < bestD) { bestD = d; best = c.id; }
      }
      col = best;
    }
    const body = colBodies.current[col];
    const cards = [...body.querySelectorAll("[data-card]")].filter(el => el.dataset.card !== dragId);
    let index = cards.length;
    for (let i = 0; i < cards.length; i++) {
      const r = cards[i].getBoundingClientRect();
      if (py < r.top + r.height / 2) { index = i; break; }
    }
    return { col, index };
  };

  const onCardPointerDown = (e, task) => {
    if (e._kbd) { onOpen(task); return; }
    if (e.button !== undefined && e.button !== 0) return;
    const cardEl = e.currentTarget;
    const rect = cardEl.getBoundingClientRect();
    const start = { x: e.clientX, y: e.clientY };
    const offset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
    dragRef.current = { id: task.id, task, started: false, start, offset, w: rect.width };
    try { cardEl.setPointerCapture(e.pointerId); } catch (err) {}

    const move = (ev) => {
      const d = dragRef.current; if (!d) return;
      if (!d.started) {
        if (Math.hypot(ev.clientX - start.x, ev.clientY - start.y) < 6) return;
        d.started = true; FX.sfx.play("pick");
      }
      const drop = computeDrop(ev.clientX, ev.clientY, d.id);
      setDrag({ id: d.id, task: d.task, w: d.w,
        gx: ev.clientX - d.offset.x, gy: ev.clientY - d.offset.y,
        col: drop.col, index: drop.index });
    };
    const up = (ev) => {
      const d = dragRef.current;
      window.removeEventListener("pointermove", move);
      window.removeEventListener("pointerup", up);
      try { cardEl.releasePointerCapture(ev.pointerId); } catch (err) {}
      if (d && d.started) {
        const drop = computeDrop(ev.clientX, ev.clientY, d.id);
        onMove(d.id, drop.col, drop.index);
        FX.sfx.play("drop");
      } else if (d) {
        onOpen(d.task);
      }
      dragRef.current = null;
      setDrag(null);
    };
    window.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
  };

  return (
    <div className="board-wrap">
      <div className="board">
        {Store.COLUMNS.map(col => {
          const items = byCol[col.id];
          const showCongrats = col.id === "todo" && items.length === 0 && !filterActive;
          const isOver = drag && drag.col === col.id;
          return (
            <section key={col.id} className={"column" + (isOver ? " drop-active" : "")}
              data-screen-label={col.title}>
              <div className="col-head">
                <span className="col-dot" style={{ background: col.dot }} />
                <span className="col-title">{col.title}</span>
                <span className={"col-count" + (bumps[col.id] ? " bump" : "")}>{counts[col.id]}</span>
              </div>
              <div className="col-body" ref={el => (colBodies.current[col.id] = el)}>
                {showCongrats && <Congrats />}
                {items.map((t, i) => (
                  <React.Fragment key={t.id}>
                    {isOver && drag.index === i && <div className="drop-ph show" />}
                    <Card task={t} pct={Store.taskProgress(t)}
                      selected={selectedId === t.id} popping={popId === t.id}
                      onOpenImages={onOpenImages}
                      onPointerDown={(e) => onCardPointerDown(e, t)} />
                  </React.Fragment>
                ))}
                {isOver && drag.index >= items.length && <div className="drop-ph show" />}
                {!showCongrats && items.length === 0 && !drag && (
                  <div style={{ color: "var(--txt-4)", fontSize: 13, textAlign: "center", padding: "24px 0" }}>
                    {filterActive ? "Nenhuma tarefa" : "Vazio"}
                  </div>
                )}
              </div>
              <button className="col-add" onClick={() => onAdd(col.id)}>
                <window.Ic.Plus size={16} /> Adicionar tarefa
              </button>
            </section>
          );
        })}
      </div>

      {drag && <GhostCard drag={drag} />}
    </div>
  );
}

function GhostCard({ drag }) {
  const { Store } = window;
  return (
    <div className="card ghost" style={{ left: drag.gx, top: drag.gy, "--ghost-w": drag.w + "px" }}>
      <div className="card-title">{drag.task.title}</div>
      <div className="tags">
        <Tag kind="cat" value={drag.task.category} />
        {drag.task.priority === "alta" && <Tag kind="prio" value={drag.task.priority} />}
      </div>
      <ProgressBar pct={Store.taskProgress(drag.task)} />
    </div>
  );
}

Object.assign(window, { Board, Card, Tag, ProgressBar, Congrats, GhostCard });
