/**
 * <swim-lanes> web component
 *
 * Renders colored vertical bars alongside a release timeline.
 * Each bar grows from the BOTTOM of the timeline upward to the top edge
 * of the last release card deployed to that environment.
 * Labels are rendered at the bottom of each bar, rotated vertically.
 *
 * Usage:
 *   <swim-lanes>
 *     <div data-lane="staging"></div>
 *     <div data-lane="prod"></div>
 *     <div data-swimlane-timeline>
 *       <div data-release data-envs="staging,prod">...</div>
 *       <div data-release data-envs="staging">...</div>
 *     </div>
 *   </swim-lanes>
 */

const ENV_COLORS = {
  prod: ["#f472b6", "#ec4899"],
  production: ["#f472b6", "#ec4899"],
  preprod: ["#fdba74", "#f97316"],
  "pre-prod": ["#fdba74", "#f97316"],
  staging: ["#fbbf24", "#ca8a04"],
  stage: ["#fbbf24", "#ca8a04"],
  dev: ["#a78bfa", "#7c3aed"],
  development: ["#a78bfa", "#7c3aed"],
  test: ["#67e8f9", "#0891b2"],
};

const DEFAULT_COLORS = ["#d1d5db", "#9ca3af"];

function envColors(name) {
  const lower = name.toLowerCase();
  if (ENV_COLORS[lower]) return ENV_COLORS[lower];
  for (const [key, colors] of Object.entries(ENV_COLORS)) {
    if (lower.includes(key)) return colors;
  }
  return DEFAULT_COLORS;
}

class SwimLanes extends HTMLElement {
  connectedCallback() {
    this.style.display = "flex";
    this._render();
    this._ro = new ResizeObserver(() => this._render());
    const timeline = this.querySelector("[data-swimlane-timeline]");
    if (timeline) {
      this._ro.observe(timeline);
      // Re-render when details elements are toggled (show/hide commits)
      timeline.addEventListener("toggle", () => this._render(), true);
    }
  }

  disconnectedCallback() {
    if (this._ro) this._ro.disconnect();
  }

  _render() {
    const timeline = this.querySelector("[data-swimlane-timeline]");
    if (!timeline) return;

    const cards = Array.from(timeline.querySelectorAll("[data-release]"));
    if (cards.length === 0) return;

    const timelineRect = timeline.getBoundingClientRect();
    const lanes = Array.from(this.querySelectorAll("[data-lane]"));

    for (const lane of lanes) {
      const env = lane.dataset.lane;
      const [barColor, labelColor] = envColors(env);

      // Find the LAST (bottommost) card deployed to this env
      let lastCard = null;
      for (const card of cards) {
        const envs = (card.dataset.envs || "")
          .split(",")
          .map((s) => s.trim())
          .filter(Boolean);
        if (envs.includes(env)) lastCard = card;
      }

      // Bar height: from bottom of timeline up to top of the last deployed card
      let barHeight = 0;
      if (lastCard) {
        const cardRect = lastCard.getBoundingClientRect();
        barHeight = timelineRect.bottom - cardRect.top;
      }

      // Style the lane container
      lane.style.width = "14px";
      lane.style.marginRight = "4px";
      lane.style.position = "relative";
      lane.style.minHeight = timelineRect.height + "px";
      lane.style.flexShrink = "0";

      // Create or update bar (anchored to bottom)
      let bar = lane.querySelector(".lane-bar");
      if (!bar) {
        bar = document.createElement("div");
        bar.className = "lane-bar";
        bar.style.position = "absolute";
        bar.style.bottom = "0";
        bar.style.left = "0";
        bar.style.width = "100%";
        bar.style.borderRadius = "9999px";
        lane.appendChild(bar);
      }
      bar.style.height = barHeight + "px";
      bar.style.backgroundColor = barColor;

      // Place dots on the lane for each card deployed to this env
      const existingDots = lane.querySelectorAll(".lane-dot");
      let dotIndex = 0;
      for (const card of cards) {
        const envs = (card.dataset.envs || "")
          .split(",")
          .map((s) => s.trim())
          .filter(Boolean);
        if (!envs.includes(env)) continue;

        const avatar = card.querySelector("[data-avatar]");
        const anchor = avatar || card;
        const anchorRect = anchor.getBoundingClientRect();
        const centerY = anchorRect.top + anchorRect.height / 2 - timelineRect.top;

        let dot = existingDots[dotIndex];
        if (!dot) {
          dot = document.createElement("div");
          dot.className = "lane-dot";
          dot.style.position = "absolute";
          dot.style.left = "50%";
          dot.style.transform = "translateX(-50%)";
          dot.style.width = "8px";
          dot.style.height = "8px";
          dot.style.borderRadius = "50%";
          dot.style.backgroundColor = "#fff";
          dot.style.border = "2px solid " + barColor;
          dot.style.zIndex = "1";
          lane.appendChild(dot);
        }
        dot.style.top = centerY - 4 + "px";
        dot.style.borderColor = barColor;
        dotIndex++;
      }
      // Remove extra dots from previous renders
      for (let i = dotIndex; i < existingDots.length; i++) {
        existingDots[i].remove();
      }

      // Create or update label (at the very bottom, below bars)
      let label = lane.querySelector(".lane-label");
      if (!label) {
        label = document.createElement("span");
        label.className = "lane-label";
        label.style.position = "absolute";
        label.style.bottom = "-4px";
        label.style.left = "50%";
        label.style.writingMode = "vertical-lr";
        label.style.transform = "translateX(-50%) translateY(100%) rotate(180deg)";
        label.style.fontSize = "10px";
        label.style.fontWeight = "500";
        label.style.whiteSpace = "nowrap";
        label.style.paddingTop = "6px";
        lane.appendChild(label);
      }
      label.textContent = env;
      label.style.color = labelColor;
    }
  }
}

customElements.define("swim-lanes", SwimLanes);
