// Gantt — hybrid parallel workflow with hard/soft dependencies + Exec/Admin views.
// window.Gantt({ phases, mode, startISO, todayDay, totalDays })
(function () {
  const DAY = 5.4;      // px per day
  const LBL = 178;      // label column width
  const HEAD = 48;      // header height
  const ROWH = 34;      // admin sub-row height
  const BAR = 24;       // bar height
  const PAD = 7;        // vertical padding inside lane
  const TH_MONTHS = ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."];

  function monthSegments(startISO, totalDays) {
    const start = new Date(startISO + "T00:00:00");
    const segs = [];
    let cursor = new Date(start);
    let dayIdx = 0;
    while (dayIdx < totalDays) {
      const m = cursor.getMonth(), y = cursor.getFullYear();
      const monthStart = new Date(y, m, 1);
      const monthEnd = new Date(y, m + 1, 1);
      const daysInMonth = Math.round((monthEnd - monthStart) / 86400000);
      const dayOfMonth = cursor.getDate() - 1;
      const remaining = daysInMonth - dayOfMonth;
      const span = Math.min(remaining, totalDays - dayIdx);
      segs.push({ label: TH_MONTHS[m] + (m === 0 ? " " + (y + 543).toString().slice(2) : ""), x: dayIdx * DAY, w: span * DAY });
      dayIdx += span;
      cursor = new Date(monthEnd);
    }
    return segs;
  }

  // greedy interval packing -> assign subRow so parallel tasks stack
  function pack(tasks) {
    const rows = [];
    const sorted = tasks.slice().sort((a, b) => a.s - b.s);
    const placed = sorted.map((t) => {
      const te = window.isMilestone(t) ? t.s + 4 : t.e;
      let r = rows.findIndex((row) => row.every((iv) => t.s >= iv.e + 1 || te <= iv.s - 1));
      if (r === -1) { r = rows.length; rows.push([]); }
      rows[r].push({ s: t.s, e: te });
      return { ...t, subRow: r };
    });
    return { placed, rowCount: Math.max(1, rows.length) };
  }

  window.Gantt = function Gantt({ phases, mode = "admin", startISO, todayDay, totalDays }) {
    const months = monthSegments(startISO, totalDays);
    const trackW = totalDays * DAY;

    // build lanes + position map
    const lanes = [];
    const posMap = {}; // taskId -> {x, w, cy, isMile}
    let y = HEAD;
    phases.forEach((ph) => {
      let laneH, packed = null;
      if (mode === "exec") {
        laneH = PHROW;
      } else {
        packed = pack(ph.tasks);
        laneH = Math.max(1, packed.rowCount) * ROWH + 10;
        packed.placed.forEach((t) => {
          const x = LBL + t.s * DAY;
          const w = window.isMilestone(t) ? 0 : Math.max((t.e - t.s) * DAY, 20);
          const cy = y + 5 + t.subRow * ROWH + BAR / 2;
          posMap[t.id] = { x, w, cy, isMile: window.isMilestone(t) };
        });
      }
      lanes.push({ ph, top: y, h: laneH, packed });
      y += laneH;
    });
    const totalH = y;
    const PHROW_DEF = 46;

    // dependency connectors (admin only)
    const connectors = [];
    if (mode === "admin") {
      phases.forEach((ph) => ph.tasks.forEach((t) => {
        (t.deps || []).forEach((dep, i) => {
          const a = posMap[dep.from], b = posMap[t.id];
          if (!a || !b) return;
          const sx = a.isMile ? a.x : a.x + a.w;
          const sy = a.cy;
          const ex = b.x;
          const ey = b.cy;
          connectors.push({ key: t.id + "-" + dep.from + i, sx, sy, ex, ey, type: dep.type });
        });
      }));
    }

    function pathFor(c) {
      const midx = Math.max(c.sx + 9, c.ex - 12);
      return `M ${c.sx} ${c.sy} H ${c.sx + 9} V ${c.ey} H ${c.ex - 2}`;
    }

    return (
      <div className="gantt-scroll">
        <div className="gantt" style={{ width: LBL + trackW, height: totalH, "--lblw": LBL + "px" }}>
          {/* header */}
          <div className="gantt-head" style={{ position: "absolute", top: 0, left: 0, right: 0, height: HEAD }}>
            <div className="gantt-row-label" style={{ width: LBL, height: HEAD }} />
            <div className="gantt-months" style={{ width: trackW, height: HEAD }}>
              {months.map((m, i) => (
                <div className="gantt-month" key={i} style={{ left: m.x, width: m.w, height: HEAD }}>{m.label}</div>
              ))}
            </div>
          </div>

          {/* lanes */}
          {lanes.map(({ ph, top, h, packed }, idx) => (
            <div className="gantt-lane" key={ph.id} style={{ position: "absolute", top, left: 0, right: 0, height: h }}>
              <div className="lane-label" style={{ width: LBL, height: h }}>
                <span className="ph-no">{idx + 1}</span>
                <div><div className="ll-n">{ph.name}</div><div className="ll-s">{ph.en} · {ph.ownerInit}</div></div>
              </div>
              <div className="lane-track" style={{ width: trackW }}>
                {(mode === "exec" || !ph.tasks || ph.tasks.length === 0) ? (
                  <>
                    <div className={"gbar phase " + ph.status} style={{ left: ph.s * DAY, width: Math.max((ph.e - ph.s) * DAY, 20), top: h / 2 - 16 }} />
                    <div className={"gbar " + ph.status} style={{ left: ph.s * DAY, width: Math.max((ph.e - ph.s) * DAY, 20), top: h / 2 - 12 }}>
                      {ph.name} · {ph.progress}%
                    </div>
                    {(ph.tasks || []).filter((t) => window.isMilestone(t)).map((t) => (
                      <React.Fragment key={t.id}>
                        <div className={"gmile " + t.status} style={{ left: t.s * DAY, top: h / 2 - 8 }} />
                        <div className="gmile-lbl" style={{ left: t.s * DAY + 12, top: h / 2 - 7 }}>{t.name}</div>
                      </React.Fragment>
                    ))}
                  </>
                ) : (
                  packed.placed.map((t) => {
                    const x = t.s * DAY;
                    if (window.isMilestone(t)) {
                      const top = 5 + t.subRow * ROWH + BAR / 2 - 8;
                      return (
                        <React.Fragment key={t.id}>
                          <div className={"gmile " + t.status} style={{ left: x, top }} />
                          <div className="gmile-lbl" style={{ left: x + 12, top: top + 1 }}>{t.name}</div>
                        </React.Fragment>
                      );
                    }
                    const w = Math.max((t.e - t.s) * DAY, 20);
                    return (
                      <div className={"gbar " + t.status} key={t.id} style={{ left: x, width: w, top: 5 + t.subRow * ROWH }} title={t.name}>
                        {t.status === "active" && <span className="gfill" style={{ width: "55%" }} />}
                        {t.name}
                      </div>
                    );
                  })
                )}
              </div>
            </div>
          ))}

          {/* today marker */}
          <div className="gantt-today" style={{ left: LBL + todayDay * DAY }}><div className="tdot" /><div className="tlbl">วันนี้</div></div>

          {/* dependency connectors */}
          {mode === "admin" && (
            <svg className="gantt-svg" style={{ width: LBL + trackW, height: totalH }}>
              <defs>
                <marker id="ah" markerWidth="7" markerHeight="7" refX="5.5" refY="3" orient="auto">
                  <path d="M0,0 L6,3 L0,6 Z" fill="var(--ink2)" />
                </marker>
                <marker id="ahs" markerWidth="7" markerHeight="7" refX="5.5" refY="3" orient="auto">
                  <path d="M0,0 L6,3 L0,6 Z" fill="var(--muted)" />
                </marker>
              </defs>
              {connectors.map((c) => (
                <path key={c.key} d={pathFor(c)} fill="none"
                  stroke={c.type === "hard" ? "var(--ink2)" : "var(--muted)"} strokeWidth="1.5"
                  strokeDasharray={c.type === "soft" ? "4 3" : "0"}
                  markerEnd={c.type === "hard" ? "url(#ah)" : "url(#ahs)"} />
              ))}
            </svg>
          )}
        </div>
      </div>
    );
  };
})();
