// zephyr-timeline.jsx — time-axis view with weekly grid, milestone rail,
// lane rows, and SVG dependency connectors.

const { EpicCard: _TL_EpicCard, Drawer: _TL_Drawer, StatusChip: TL_StatusChip,
        LaneChip: TL_LaneChip, fmtDate: _tlFmtDate, daysBetween: _tlDaysBetween,
        laneById: _tlLaneById } = window.ZephyrComponents;
const TL_D = window.ZEPHYR_DATA;

function TimelineView({ onEpicClick, laneFilter = "all" }) {
  // Horizon: May 1 → Jul 31 2026
  const start = "2026-05-01";
  const end   = "2026-07-31";
  const totalDays = _tlDaysBetween(start, end);

  // Epics inside horizon
  const epics = TL_D.epics.filter(e => e.end >= start && e.start <= end && (laneFilter === "all" || e.lane === laneFilter));

  // Group by lane, pack rows per lane
  const lanes = TL_D.workstreams.filter(w => laneFilter === "all" || w.id === laneFilter).map(w => ({
    ...w,
    epics: epics.filter(e => e.lane === w.id),
  })).filter(l => l.epics.length > 0);

  // Row height + lane spacing
  const ROW_H = 34;
  const LANE_PAD = 6;
  const LANE_HEAD = 28;

  // Pack: simple greedy rows per lane
  const pack = (es) => {
    const sorted = [...es].sort((a, b) => a.start.localeCompare(b.start));
    const rows = [];
    sorted.forEach(e => {
      let placed = false;
      for (let i = 0; i < rows.length; i++) {
        if (rows[i][rows[i].length - 1].end < e.start) {
          rows[i].push({ ...e, row: i });
          placed = true; break;
        }
      }
      if (!placed) rows.push([{ ...e, row: rows.length }]);
    });
    return rows.flat();
  };

  const laneRows = lanes.map(l => ({ ...l, packed: pack(l.epics) }));
  const laneHeights = laneRows.map(l => {
    const maxRow = l.packed.reduce((m, e) => Math.max(m, e.row), 0);
    return LANE_HEAD + (maxRow + 1) * (ROW_H + LANE_PAD) + 8;
  });
  const laneTops = [];
  let cum = 0;
  laneHeights.forEach(h => { laneTops.push(cum); cum += h; });
  const totalHeight = cum;

  // Date → %
  const pctOf = (d) => (_tlDaysBetween(start, d) / totalDays) * 100;

  // Weekly ticks
  const ticks = [];
  let cur = new Date(start);
  const endD = new Date(end);
  while (cur <= endD) {
    const iso = cur.toISOString().slice(0, 10);
    ticks.push({ iso, left: pctOf(iso), isMonth: cur.getDate() <= 7 });
    cur.setDate(cur.getDate() + 7);
  }

  // Build epic position lookup (absolute px from top of lanes-area)
  const posMap = {};
  laneRows.forEach((l, li) => {
    l.packed.forEach(e => {
      const top = laneTops[li] + LANE_HEAD + e.row * (ROW_H + LANE_PAD);
      posMap[e.id] = {
        top,
        bottom: top + ROW_H,
        leftPct: pctOf(e.start),
        rightPct: pctOf(e.end),
        row: e.row,
      };
    });
  });

  // Today marker
  const today = "2026-04-24";
  const todayPct = pctOf(today);

  return (
    <div className="zr-tl">
      {/* Milestone rail */}
      <div className="zr-tl-rail">
        <div className="zr-tl-rail-line" />
        {TL_D.milestones.map(m => {
          const left = pctOf(m.date);
          if (left < 0 || left > 100) return null;
          return (
            <div key={m.id}
                 className={`zr-tl-pin zr-tl-pin-${m.kind}`}
                 style={{ left: `${left}%` }}
                 title={m.label}>
              <div className="flag-body">
                <div className="date">{_tlFmtDate(m.date)}</div>
                <div className="label">{m.label}</div>
              </div>
              <div className="stem" />
              <div className="dot" />
            </div>
          );
        })}
      </div>

      {/* Axis (weekly ticks) */}
      <div className="zr-tl-axis">
        {ticks.map((t, i) => {
          const d = new Date(t.iso);
          const mon = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][d.getMonth()];
          return (
            <div key={i} className={`zr-tl-tick ${t.isMonth ? "month" : ""}`} style={{ left: `${t.left}%` }}>
              <span className="lbl">{t.isMonth ? mon : d.getDate()}</span>
            </div>
          );
        })}
        {todayPct >= 0 && todayPct <= 100 && (
          <div className="zr-tl-today" style={{ left: `${todayPct}%` }}>
            <div className="l"></div>
            <div className="lbl">TODAY · {_tlFmtDate(today)}</div>
          </div>
        )}
      </div>

      {/* Lane rows */}
      <div className="zr-tl-body" style={{ height: `${totalHeight}px` }}>
        {/* weekly grid lines */}
        <div className="zr-tl-grid">
          {ticks.map((t, i) => (
            <div key={i} className={`gl ${t.isMonth ? "m" : ""}`} style={{ left: `${t.left}%` }} />
          ))}
          {todayPct >= 0 && todayPct <= 100 && (
            <div className="gl today" style={{ left: `${todayPct}%` }} />
          )}
        </div>

        {/* Dependency connectors (SVG overlay) */}
        <svg className="zr-tl-deps" width="100%" height={totalHeight} preserveAspectRatio="none">
          <defs>
            <marker id="zr-arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
              <path d="M0,0 L10,5 L0,10 z" fill="#A82830" />
            </marker>
          </defs>
          {epics.flatMap(e => (e.deps || []).map(depId => {
            const a = posMap[depId];
            const b = posMap[e.id];
            if (!a || !b) return null;
            const key = `${depId}-${e.id}`;
            // We can't use % for SVG path in mixed units, use calc via foreignObject — instead draw in percent-x using getComputedStyle at render.
            // Trick: we use an SVG with viewBox 0 0 100 h so x is in %.
            return { key, a, b };
          })).filter(Boolean).length === 0 ? null : null}
          {/* Replaced by DepsSvg below */}
        </svg>
        <DepsSvg epics={epics} posMap={posMap} totalHeight={totalHeight} />

        {/* Lanes */}
        {laneRows.map((l, li) => (
          <div key={l.id} className="zr-tl-lane" style={{ top: `${laneTops[li]}px`, height: `${laneHeights[li]}px` }}>
            <div className="zr-tl-lane-head" style={{ borderLeftColor: l.color }}>
              <span className="zr-lane-chip" style={{ color: l.color }}>{l.label}</span>
              <span className="ct">{l.epics.length}</span>
            </div>
            {l.packed.map(e => {
              const left = pctOf(e.start);
              const width = Math.max(2, pctOf(e.end) - pctOf(e.start));
              return (
                <div key={e.id}
                     className={`zr-tl-bar ${e.status === "done" ? "zr-done-hide" : ""}`}
                     style={{
                       top: `${LANE_HEAD + e.row * (ROW_H + LANE_PAD)}px`,
                       left: `${left}%`,
                       width: `${width}%`,
                       "--lane-color": l.color,
                     }}
                     onClick={() => onEpicClick(e)}
                     role="button"
                     tabIndex={0}
                     onKeyDown={(ev) => { if (ev.key === "Enter") onEpicClick(e); }}
                     data-epic-id={e.id}>
                  <div className="bar-inner">
                    <span className="title">{e.title}</span>
                    <TL_StatusChip status={e.status} />
                  </div>
                </div>
              );
            })}
          </div>
        ))}
      </div>
    </div>
  );
}

// ── Dependency SVG (percent-X, pixel-Y) ─────────────────────────────────────
function DepsSvg({ epics, posMap, totalHeight }) {
  const arrows = [];
  epics.forEach(e => {
    (e.deps || []).forEach(depId => {
      const a = posMap[depId], b = posMap[e.id];
      if (!a || !b) return;
      arrows.push({ key: `${depId}-${e.id}`, a, b });
    });
  });

  return (
    <svg className="zr-tl-deps"
         viewBox={`0 0 100 ${totalHeight}`}
         preserveAspectRatio="none"
         width="100%" height={totalHeight}>
      <defs>
        <marker id="zr-arrow-2" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
          <path d="M0,0 L10,5 L0,10 z" fill="#A82830" />
        </marker>
      </defs>
      {arrows.map(({ key, a, b }) => {
        const x1 = a.rightPct;
        const y1 = (a.top + a.bottom) / 2;
        const x2 = b.leftPct;
        const y2 = (b.top + b.bottom) / 2;
        // If dep finishes after consumer starts, arrow would go backward — just draw.
        const midX = (x1 + x2) / 2;
        const d = `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`;
        return (
          <path key={key} d={d}
                fill="none" stroke="#A82830" strokeWidth="0.4"
                strokeDasharray="1.2 1" opacity="0.75"
                vectorEffect="non-scaling-stroke"
                markerEnd="url(#zr-arrow-2)" />
        );
      })}
    </svg>
  );
}

window.ZephyrTimeline = TimelineView;
