/* ============================================================
   views_overview.jsx — 儀表板統計 + 甘特時間軸 + 清單視圖
   ============================================================ */

/* ---------- stat header ---------- */
function StatHeader({ tasks }) {
  const total = tasks.length;
  const overall = total ? tasks.reduce((a, t) => a + taskProgress(t), 0) / total : 0;
  const active = tasks.filter((t) => taskProgress(t) > 0 && taskProgress(t) < 1 && !isBlocked(t)).length;
  const blocked = tasks.filter((t) => isBlocked(t)).length;
  const done = tasks.filter((t) => taskProgress(t) >= 1).length;

  const stats = [
    { k: "追蹤任務", v: total, sub: `${done} 已完成`, color: "var(--ink)" },
    { k: "進行中", v: active, sub: "AI 正在處理", color: "var(--accent)" },
    { k: "待我決策", v: blocked, sub: blocked ? "需要您拍板" : "目前無阻礙", color: blocked ? "var(--block)" : "var(--ink-3)" },
  ];

  return (
    <div style={{ display: "grid", gridTemplateColumns: "minmax(220px, 1.1fr) repeat(3, 1fr)", gap: 14, marginBottom: 18 }} className="stat-grid">
      <div className="card" style={{ padding: "18px 20px", display: "flex", alignItems: "center", gap: 18 }}>
        <ProgressRing value={overall} size={64} stroke={6} />
        <div>
          <div style={{ fontSize: 12.5, color: "var(--ink-3)", fontWeight: 600 }}>整體完成度</div>
          <div style={{ fontSize: 26, fontWeight: 700, letterSpacing: "-0.02em", lineHeight: 1.1 }}>
            {Math.round(overall * 100)}<span style={{ fontSize: 15, color: "var(--ink-3)" }}>%</span>
          </div>
          <div style={{ fontSize: 12, color: "var(--ink-3)" }}>跨 {total} 個專案任務</div>
        </div>
      </div>
      {stats.map((s) => (
        <div key={s.k} className="card" style={{ padding: "18px 20px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
          <div style={{ fontSize: 12.5, color: "var(--ink-3)", fontWeight: 600 }}>{s.k}</div>
          <div className="mono" style={{ fontSize: 30, fontWeight: 600, color: s.color, letterSpacing: "-0.02em", lineHeight: 1.15 }}>{s.v}</div>
          <div style={{ fontSize: 12, color: "var(--ink-3)" }}>{s.sub}</div>
        </div>
      ))}
    </div>
  );
}

/* ---------- gantt ---------- */
function GanttView({ tasks, onOpen, pxDay = 17, onShiftStage, justUpdatedId }) {
  const range = useMemo(() => {
    const starts = tasks.map((t) => d(t.stages[0].start).getTime());
    const ends = tasks.map((t) => d(t.deadline).getTime());
    let min = Math.min(...starts), max = Math.max(...ends);
    min -= 2 * DAY; max += 3 * DAY;
    return { min, max, days: Math.round((max - min) / DAY) };
  }, [tasks]);

  const startStr = new Date(range.min).toISOString().slice(0, 10);
  const width = range.days * pxDay;
  const todayX = daysBetween(startStr, TODAY) * pxDay;

  // ----- stage drag -----
  const dragRef = useRef(null);
  const suppress = useRef(false);
  const [preview, setPreview] = useState(null); // {taskId, key, deltaDays}
  useEffect(() => {
    function move(e) {
      const dr = dragRef.current; if (!dr) return;
      if (Math.abs(e.clientX - dr.startX) > 4) dr.moved = true;
      const dd = Math.round((e.clientX - dr.startX) / pxDay);
      setPreview({ taskId: dr.taskId, key: dr.key, deltaDays: dd });
    }
    function up(e) {
      const dr = dragRef.current; if (!dr) return;
      const dd = Math.round((e.clientX - dr.startX) / pxDay);
      if (dr.moved && dd !== 0 && onShiftStage) { onShiftStage(dr.taskId, dr.key, dd); suppress.current = true; }
      else if (dr.moved) suppress.current = true;
      dragRef.current = null;
      setPreview(null);
    }
    window.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
    return () => { window.removeEventListener("pointermove", move); window.removeEventListener("pointerup", up); };
  }, [pxDay, onShiftStage]);
  function barDown(e, t, s) {
    e.stopPropagation();
    dragRef.current = { taskId: t.id, key: s.key, startX: e.clientX, moved: false };
  }
  function rowClick(t) {
    if (suppress.current) { suppress.current = false; return; }
    onOpen(t.id);
  }

  // month + week ticks
  const ticks = [];
  for (let i = 0; i <= range.days; i++) {
    const date = new Date(range.min + i * DAY);
    if (date.getDay() === 1) ticks.push({ x: i * pxDay, label: `${date.getMonth() + 1}/${date.getDate()}` });
  }
  const months = [];
  let lastM = -1;
  for (let i = 0; i <= range.days; i++) {
    const date = new Date(range.min + i * DAY);
    if (date.getMonth() !== lastM) { lastM = date.getMonth(); months.push({ x: i * pxDay, label: `${date.getFullYear()} 年 ${date.getMonth() + 1} 月` }); }
  }

  const rowH = 64;
  const labelW = 240;
  const idxOf = Object.fromEntries(tasks.map((t, i) => [t.id, i]));

  return (
    <div className="card" style={{ overflow: "hidden" }}>
      <div style={{ display: "flex" }}>
        {/* left labels */}
        <div style={{ width: labelW, flexShrink: 0, borderRight: "1px solid var(--line)", background: "var(--surface)", zIndex: 2 }}>
          <div style={{ height: 52, borderBottom: "1px solid var(--line)", display: "flex", alignItems: "flex-end", padding: "0 16px 8px", fontSize: 11.5, fontWeight: 600, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.06em" }}>任務</div>
          {tasks.map((t) => {
            const cnt = taskCounts(t);
            return (
              <button key={t.id} onClick={() => onOpen(t.id)} style={{
                height: rowH, width: "100%", border: "none", background: "none", textAlign: "left",
                padding: "0 16px", borderBottom: "1px solid var(--line-soft)", cursor: "pointer",
                display: "flex", flexDirection: "column", justifyContent: "center", gap: 4,
              }} className="gantt-label">
                <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
                  <span style={{ width: 5, height: 5, borderRadius: 50, background: PRIO[t.priority].color, flexShrink: 0 }} />
                  <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.title}</span>
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span className="mono" style={{ fontSize: 11, color: "var(--ink-3)" }}>{cnt.done}/{cnt.total}</span>
                  <StatusChip task={t} />
                </div>
              </button>
            );
          })}
        </div>

        {/* right timeline */}
        <div style={{ overflowX: "auto", flex: 1 }}>
          <div style={{ width, position: "relative" }}>
            {/* header */}
            <div style={{ height: 52, borderBottom: "1px solid var(--line)", position: "relative" }}>
              {months.map((m, i) => (
                <div key={i} style={{ position: "absolute", left: m.x, top: 6, fontSize: 11.5, fontWeight: 700, color: "var(--ink-2)", whiteSpace: "nowrap", paddingLeft: 6 }}>{m.label}</div>
              ))}
              {ticks.map((tk, i) => (
                <div key={i} className="mono" style={{ position: "absolute", left: tk.x, bottom: 7, fontSize: 10, color: "var(--ink-3)", whiteSpace: "nowrap", borderLeft: "1px solid var(--line)", paddingLeft: 5, height: 12, display: "flex", alignItems: "center" }}>{tk.label}</div>
              ))}
            </div>

            {/* grid lines */}
            <div style={{ position: "absolute", top: 52, bottom: 0, left: 0, right: 0, pointerEvents: "none" }}>
              {ticks.map((tk, i) => (
                <div key={i} style={{ position: "absolute", left: tk.x, top: 0, bottom: 0, width: 1, background: "var(--line-soft)" }} />
              ))}
            </div>

            {/* today line */}
            {todayX >= 0 && todayX <= width && (
              <div style={{ position: "absolute", left: todayX, top: 36, bottom: 0, width: 2, background: "var(--accent)", zIndex: 3, pointerEvents: "none" }}>
                <div style={{ position: "absolute", top: -2, left: -22, fontSize: 9.5, fontWeight: 700, color: "white", background: "var(--accent)", padding: "1px 6px", borderRadius: 20, whiteSpace: "nowrap" }} className="mono">TODAY</div>
              </div>
            )}

            {/* dependency arrows */}
            <svg width={width} height={tasks.length * rowH} style={{ position: "absolute", left: 0, top: 52, pointerEvents: "none", zIndex: 4, overflow: "visible" }}>
              <defs>
                <marker id="dep-arrow" markerWidth="9" markerHeight="9" refX="6.5" refY="4" orient="auto">
                  <path d="M0 0 L7 4 L0 8 z" fill="var(--accent)" />
                </marker>
              </defs>
              {tasks.map((t, si) => (t.deps || []).map((depId) => {
                const pi = idxOf[depId]; if (pi == null) return null;
                const pred = tasks[pi];
                const fromX = daysBetween(startStr, pred.stages[0].end) * pxDay;
                const fromY = pi * rowH + rowH / 2;
                const toX = daysBetween(startStr, t.stages[0].start) * pxDay;
                const toY = si * rowH + rowH / 2;
                const cp = Math.max(30, Math.abs(toX - fromX) * 0.45);
                const dpath = `M ${fromX} ${fromY} C ${fromX + cp} ${fromY}, ${toX - cp} ${toY}, ${toX} ${toY}`;
                return (
                  <g key={t.id + depId}>
                    <circle cx={fromX} cy={fromY} r="3.5" fill="var(--accent)" />
                    <path d={dpath} fill="none" stroke="var(--accent)" strokeWidth="2" strokeDasharray="6 4" markerEnd="url(#dep-arrow)" opacity="0.85" />
                  </g>
                );
              }))}
            </svg>

            {/* rows */}
            {tasks.map((t) => (
              <div key={t.id} onClick={() => rowClick(t)} className={"gantt-row" + (t.id === justUpdatedId ? " gantt-flash" : "")} style={{
                height: rowH, width: "100%", display: "block", position: "relative",
                borderBottom: "1px solid var(--line-soft)", cursor: "pointer",
              }}>
                {t.stages.map((s) => {
                  const isDrag = preview && preview.taskId === t.id && preview.key === s.key;
                  const off = isDrag ? preview.deltaDays * pxDay : 0;
                  const x = daysBetween(startStr, s.start) * pxDay + off;
                  const w = Math.max(daysBetween(s.start, s.end) * pxDay, pxDay);
                  const color = STAGE_COLOR[s.key];
                  const prog = stageProgress(s);
                  const def = window.STAGE_DEFS.find((x) => x.key === s.key);
                  let bg, fill = null, border = "none";
                  if (s.status === "done") bg = color;
                  else if (s.status === "blocked") { bg = "var(--block-soft)"; border = `1.5px dashed var(--block)`; }
                  else if (s.status === "active") { bg = "color-mix(in oklch, " + color + " 22%, var(--surface))"; fill = color; }
                  else { bg = "color-mix(in oklch, " + color + " 14%, var(--surface))"; border = `1px solid color-mix(in oklch, ${color} 40%, var(--surface))`; }
                  return (
                    <div key={s.key} title={`${def.label} · ${Math.round(prog * 100)}% · 拖曳可調整時程`}
                      onPointerDown={(e) => barDown(e, t, s)} style={{
                      position: "absolute", left: x, top: rowH / 2 - 11, width: w, height: 22,
                      background: bg, borderRadius: 6, border, overflow: "hidden",
                      display: "flex", alignItems: "center", paddingLeft: 6,
                      cursor: isDrag ? "grabbing" : "grab", zIndex: isDrag ? 6 : 1,
                      boxShadow: isDrag ? "var(--shadow-lg)" : "none",
                      transition: isDrag ? "none" : "left 0.18s ease",
                      touchAction: "none",
                    }}>
                      {fill && <div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: `${prog * 100}%`, background: color, borderRadius: 6 }} />}
                      <span style={{ position: "relative", fontSize: 10, fontWeight: 700, color: s.status === "done" || (fill && prog > 0.5) ? "white" : "var(--ink-2)", whiteSpace: "nowrap", overflow: "hidden" }}>{def.short}</span>
                      {s.status === "blocked" && <Icon name="alert" size={11} style={{ position: "relative", marginLeft: 4, color: "var(--block)" }} />}
                    </div>
                  );
                })}
                {/* deadline marker */}
                <div style={{ position: "absolute", left: daysBetween(startStr, t.deadline) * pxDay, top: rowH / 2 - 14, height: 28, width: 0, borderLeft: "2px dotted var(--ink-3)" }} title={`期限 ${fmtFull(t.deadline)}`} />
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* legend */}
      <div style={{ display: "flex", flexWrap: "wrap", gap: 14, padding: "12px 18px", borderTop: "1px solid var(--line)", fontSize: 11.5, color: "var(--ink-3)" }}>
        {window.STAGE_DEFS.map((s) => (
          <span key={s.key} style={{ display: "flex", alignItems: "center", gap: 6 }}>
            <span style={{ width: 11, height: 11, borderRadius: 3, background: STAGE_COLOR[s.key] }} />{s.label}
          </span>
        ))}
        <span style={{ display: "flex", alignItems: "center", gap: 6, marginLeft: "auto" }}>
          <span style={{ width: 0, height: 14, borderLeft: "2px dotted var(--ink-3)" }} />期限
        </span>
        <span style={{ display: "flex", alignItems: "center", gap: 6 }}>
          <svg width="22" height="10"><path d="M0 5 H20" stroke="var(--ink-3)" strokeWidth="1.5" strokeDasharray="5 3" /><path d="M16 1 L21 5 L16 9" fill="none" stroke="var(--ink-3)" strokeWidth="1.5" /></svg>相依
        </span>
        <span style={{ marginLeft: 4, fontStyle: "italic" }}>提示：拖曳色塊可調整時程</span>
      </div>
    </div>
  );
}

/* ---------- compact list (mobile-friendly) ---------- */
function ListView({ tasks, onOpen }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 11 }}>
      {tasks.map((t) => {
        const prog = taskProgress(t);
        const cur = currentStage(t);
        const cnt = taskCounts(t);
        return (
          <button key={t.id} onClick={() => onOpen(t.id)} className="card task-card" style={{
            padding: "16px 18px", textAlign: "left", display: "flex", alignItems: "center", gap: 16, width: "100%",
          }}>
            <ProgressRing value={prog} size={48} stroke={5} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 6, flexWrap: "wrap" }}>
                <span style={{ fontSize: 15, fontWeight: 700, letterSpacing: "-0.01em" }}>{t.title}</span>
                <PriorityTag priority={t.priority} />
                <StatusChip task={t} />
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", fontSize: 12, color: "var(--ink-3)" }}>
                <span style={{ display: "flex", alignItems: "center", gap: 5 }}>目前 <StageChip stage={cur} active /></span>
                <span className="mono">{cnt.done}/{cnt.total} 子任務</span>
                <span style={{ display: "flex", alignItems: "center", gap: 4 }}><Icon name="calendar" size={12} />{fmtFull(t.deadline)}</span>
              </div>
            </div>
            <Icon name="chevron" size={18} className="muted" />
          </button>
        );
      })}
    </div>
  );
}

Object.assign(window, { StatHeader, GanttView, ListView });
