/* planner-board.jsx — the week board with day columns, blocks, drag & drop */

const { useState, useRef, useEffect, useMemo, useCallback } = React;

function PlannerBoard({ state, settings, currentWeekStart, weekStartDate, activeId, onSelect, onCreate, onUpdate, onPlaceSticker, motion }) {
  const { DAY_NAMES, DAY_SHORT, fmtDate, fmtHour, fmtTime, computeLayouts, snapMin, clamp } = window.PLANNER_DATA;

  const blocks = state.blocks;
  const visibleDays = settings.includeWeekend ? 7 : 5;
  const dayColors = ["var(--c-mon)","var(--c-tue)","var(--c-wed)","var(--c-thu)","var(--c-fri)","var(--c-sat)","var(--c-sun)"];

  const startMin = settings.startHour * 60;
  const endMin = settings.endHour * 60;
  const totalMin = Math.max(endMin - startMin, 1);
  const hours = settings.endHour - settings.startHour;
  const HOUR_H = 72;
  const shelfHeight = hours * HOUR_H;

  const layouts = useMemo(() => computeLayouts(blocks), [blocks]);

  /* ---------- Drag state ---------- */
  const [drag, setDrag] = useState(null); // { id, mode: "move"|"resize", offsetMin, originDay, originStart, originEnd, hoverDay, hoverStart }
  const shelfRefs = useRef({});

  const onMouseDownBlock = (e, block, mode="move") => {
    if (e.button !== 0) return;
    e.stopPropagation();
    const rect = e.currentTarget.getBoundingClientRect();
    const clickMin = startMin + ((e.clientY - rect.top) / rect.height) * (block.end - block.start);
    setDrag({
      id: block.id,
      mode,
      offsetMin: mode === "move" ? (clickMin - block.start) : 0,
      originDay: block.dayIndex,
      originStart: block.start,
      originEnd: block.end,
      hoverDay: block.dayIndex,
      hoverStart: block.start,
      hoverEnd: block.end
    });
    onSelect(block.id);
  };

  useEffect(() => {
    if (!drag) return;
    function getDayFromX(x, y) {
      for (let d = 0; d < visibleDays; d++) {
        const el = shelfRefs.current[d];
        if (!el) continue;
        const r = el.getBoundingClientRect();
        if (x >= r.left && x <= r.right && y >= r.top - 20 && y <= r.bottom + 20) {
          return { day: d, rect: r };
        }
      }
      return null;
    }
    function onMove(e) {
      const hit = getDayFromX(e.clientX, e.clientY);
      if (!hit) return;
      const dur = drag.originEnd - drag.originStart;
      const y = clamp(e.clientY - hit.rect.top, 0, hit.rect.height);
      const minutes = startMin + (y / hit.rect.height) * totalMin;
      if (drag.mode === "move") {
        const newStart = snapMin(minutes - drag.offsetMin);
        const clampedStart = clamp(newStart, startMin, endMin - dur);
        setDrag(d => ({ ...d, hoverDay: hit.day, hoverStart: clampedStart, hoverEnd: clampedStart + dur }));
      } else {
        const newEnd = snapMin(minutes);
        const clampedEnd = clamp(newEnd, drag.originStart + 30, endMin);
        setDrag(d => ({ ...d, hoverDay: hit.day, hoverStart: drag.originStart, hoverEnd: clampedEnd }));
      }
    }
    function onUp() {
      if (!drag) return;
      if (drag.hoverDay !== drag.originDay || drag.hoverStart !== drag.originStart || drag.hoverEnd !== drag.originEnd) {
        onUpdate(drag.id, { dayIndex: drag.hoverDay, start: drag.hoverStart, end: drag.hoverEnd });
      }
      setDrag(null);
    }
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
    };
  }, [drag, visibleDays, startMin, endMin, totalMin, snapMin, clamp, onUpdate]);

  /* ---------- Sticker drop targets ---------- */
  const [stickerHover, setStickerHover] = useState(null);

  useEffect(() => {
    function onStickerMove(e) {
      const d = window.__draggingSticker;
      if (!d) return;
      const el = document.elementFromPoint(e.clientX, e.clientY);
      const block = el && el.closest && el.closest(".block");
      setStickerHover(block ? block.dataset.id : null);
    }
    function onStickerUp(e) {
      const d = window.__draggingSticker;
      if (!d) return;
      const el = document.elementFromPoint(e.clientX, e.clientY);
      const block = el && el.closest && el.closest(".block");
      if (block) {
        const r = block.getBoundingClientRect();
        onPlaceSticker(block.dataset.id, {
          kind: d.kind,
          x: ((e.clientX - r.left) / r.width) * 100,
          y: ((e.clientY - r.top) / r.height) * 100,
          rot: Math.random() * 30 - 15
        });
      }
      setStickerHover(null);
    }
    window.addEventListener("mousemove", onStickerMove);
    window.addEventListener("mouseup", onStickerUp);
    return () => {
      window.removeEventListener("mousemove", onStickerMove);
      window.removeEventListener("mouseup", onStickerUp);
    };
  }, [onPlaceSticker]);

  /* ---------- "Now" line ---------- */
  const [now, setNow] = useState(new Date());
  useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 60000);
    return () => clearInterval(t);
  }, []);
  const todayDay = ((now.getDay() + 6) % 7);
  const nowMin = now.getHours() * 60 + now.getMinutes();
  const showNowOn = (dayIdx) => {
    if (dayIdx !== todayDay) return null;
    if (nowMin < startMin || nowMin > endMin) return null;
    const ws = window.PLANNER_DATA.parseISODate(currentWeekStart);
    const todayDate = window.PLANNER_DATA.addDays(ws, todayDay);
    const realToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    if (todayDate.getTime() !== realToday.getTime()) return null;
    return ((nowMin - startMin) / totalMin) * 100;
  };

  /* ---------- Click empty slot to add ---------- */
  const onShelfClick = (e, dayIndex) => {
    if (e.target.closest(".block") || e.target.closest(".add-here")) return;
    if (drag) return;
    const r = e.currentTarget.getBoundingClientRect();
    const y = clamp(e.clientY - r.top, 0, r.height);
    const mins = snapMin(startMin + (y / r.height) * totalMin);
    onCreate({ dayIndex, start: mins, end: Math.min(mins + 45, endMin) });
  };

  return (
    <div className="board-wrap">
      <div className="board" style={{ "--day-count": visibleDays, "--hours": hours }}>
        {/* Time axis */}
        <div className="time-axis">
          {Array.from({ length: hours + 1 }).map((_, i) => {
            const h = settings.startHour + i;
            return (
              <div key={i} className="time-tick" style={{ top: `calc(110px + 6px + ${(i / hours) * 100}% * ${hours} / ${hours + 1})` }}>
                {fmtHour(h)}
              </div>
            );
          })}
        </div>

        {/* Day columns */}
        {Array.from({ length: visibleDays }).map((_, day) => {
          const date = window.PLANNER_DATA.addDays(weekStartDate, day);
          const dayColor = dayColors[day];
          const tilt = (day % 2 === 0 ? -1 : 1) * 1.2;
          const dayBlocks = blocks.filter(b => b.dayIndex === day && b.end > startMin && b.start < endMin);
          const Mascot = window.DAY_MASCOTS[day];
          const nowTop = showNowOn(day);
          const isDropTarget = drag && drag.hoverDay === day && drag.hoverDay !== drag.originDay;

          return (
            <div key={day} className="day-col" style={{ "--day-color": dayColor }}>
              <div className="day-head" style={{ "--head-tilt": `${tilt}deg` }}>
                <span className="tape tl"/>
                <span className="tape tr"/>
                <div>
                  <div className="day-name">{DAY_SHORT[day]}</div>
                  <div className="day-date">{fmtDate(date, { month: "short", day: "numeric" })}</div>
                </div>
                <div className="mascot"><Mascot/></div>
              </div>

              <div
                className={"day-shelf" + (isDropTarget ? " drop-target" : "")}
                ref={el => (shelfRefs.current[day] = el)}
                style={{ minHeight: shelfHeight + "px" }}
                onClick={(e) => onShelfClick(e, day)}
              >
                {nowTop != null && <div className="now-line" style={{ top: nowTop + "%" }}/>}

                {/* Drop ghost */}
                {drag && drag.hoverDay === day && (() => {
                  const top = ((drag.hoverStart - startMin) / totalMin) * 100;
                  const ht = ((drag.hoverEnd - drag.hoverStart) / totalMin) * 100;
                  return <div className="drop-ghost" style={{ top: top + "%", height: `max(${ht}%, 48px)` }}/>;
                })()}

                {/* Blocks */}
                {dayBlocks.map(block => {
                  const isDragging = drag && drag.id === block.id;
                  const vStart = clamp(block.start, startMin, endMin);
                  const vEnd = clamp(block.end, startMin, endMin);
                  const top = ((vStart - startMin) / totalMin) * 100;
                  const height = Math.max(((vEnd - vStart) / totalMin) * 100, 6);
                  const lay = layouts[block.id] || { col: 0, cols: 1 };
                  const left = `calc(${(100 / lay.cols) * lay.col}% + 6px)`;
                  const width = `calc(${100 / lay.cols}% - 12px)`;
                  const typeMeta = window.PLANNER_DATA.BLOCK_TYPES.find(t => t.id === block.typeId) || window.PLANNER_DATA.BLOCK_TYPES[0];
                  const TypeIcon = window.Icon[typeMeta.icon] || window.Icon.book;
                  const completion = window.PLANNER_DATA.planCompletion(block);
                  const rot = ((parseInt(block.id.slice(-2), 36) % 5) - 2) * 0.3;
                  const isHoverSticker = stickerHover === block.id;

                  return (
                    <button
                      key={block.id}
                      data-id={block.id}
                      className={"block" + (block.id === activeId ? " active" : "") + (isDragging ? " dragging" : "")}
                      style={{
                        top: isDragging ? `calc(${((drag.hoverStart - startMin) / totalMin) * 100}% )` : top + "%",
                        height: isDragging ? `max(${((drag.hoverEnd - drag.hoverStart) / totalMin) * 100}%, 48px)` : `max(${height}%, 48px)`,
                        left, width,
                        "--block-color": block.color,
                        "--rot": rot + "deg",
                        outline: isHoverSticker ? "3px dashed #2a2438" : "none",
                        outlineOffset: isHoverSticker ? "3px" : 0
                      }}
                      onMouseDown={(e) => onMouseDownBlock(e, block, "move")}
                      onClick={(e) => { e.stopPropagation(); onSelect(block.id); }}
                      onDoubleClick={(e) => { e.stopPropagation(); onSelect(block.id, true); }}
                    >
                      <span className="b-time">{fmtTime(block.start)} – {fmtTime(block.end)}</span>
                      <div className="b-title">{block.title || "Untitled"}</div>
                      <div className="b-meta">
                        <span className="b-type-icon"><TypeIcon/></span>
                        <span>{block.group || typeMeta.label}</span>
                      </div>
                      {/* Plan progress dots */}
                      <div className="b-progress">
                        {[0,1,2,3].map(i => (
                          <span key={i} className={"dot" + (completion >= (i+1)*25 ? " on" : "")}/>
                        ))}
                      </div>
                      {/* Stickers — auto-stacked top-right; dragged ones keep their coords */}
                      {block.stickers && (() => {
                        let autoIdx = 0;
                        return block.stickers.map((s, i) => {
                          const kind = typeof s === "string" ? s : s.kind;
                          const Cmp = window.Sticker[kind];
                          if (!Cmp) return null;
                          const isAuto = typeof s === "string" || s.x == null;
                          if (isAuto) {
                            const k = autoIdx++;
                            return (
                              <span key={i} className="placed-sticker"
                                style={{
                                  right: `${4 + k * 16}px`,
                                  top: `4px`,
                                  "--rot": `${(k%2?1:-1)*10}deg`,
                                }}>
                                <Cmp/>
                              </span>
                            );
                          }
                          return (
                            <span key={i} className="placed-sticker"
                              style={{
                                left: `calc(${s.x}% - 13px)`,
                                top: `calc(${s.y}% - 13px)`,
                                "--rot": (s.rot || 0) + "deg",
                              }}>
                              <Cmp/>
                            </span>
                          );
                        });
                      })()}
                      {/* Resize handle */}
                      <span
                        className="resize-handle"
                        onMouseDown={(e) => onMouseDownBlock(e, block, "resize")}
                        style={{
                          position: "absolute", left: 0, right: 0, bottom: 0, height: 10,
                          cursor: "ns-resize"
                        }}
                      />
                    </button>
                  );
                })}

                {/* Add hint */}
                <button className="add-here" onClick={(e) => {
                  e.stopPropagation();
                  onCreate({ dayIndex: day, start: startMin + 60, end: startMin + 105 });
                }} title="Add block">
                  <svg viewBox="0 0 24 24" fill="none" stroke="#2a2438" strokeWidth="3" strokeLinecap="round" style={{width:18,height:18}}>
                    <path d="M12 5v14M5 12h14"/>
                  </svg>
                </button>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

window.PlannerBoard = PlannerBoard;
