import { unsafeCSS, LitElement, nothing, html } from "lit";
import { property, query } from "lit/decorators.js";
import { customElement } from "../../decorator.js";
import componentStyle from "./poi-layer.css.js";
import "../poi-group/poi-group.js";
import "../poi-data/poi-data.js";
import { ObcPoiValue, PoiDataVisualRectPreference, isPoi, POI_ATTR } from "../building-blocks/poi/poi.js";
import { ObcPoiButtonType } from "../building-blocks/poi-button/poi-button.js";
import { buildAdjacencyMaps, buildClusters } from "./poi-layer-grouping-utils.js";
import { updateCrossingModeState } from "./poi-layer-crossing-utils.js";
import { getEffectivePoiX } from "../building-blocks/poi/poi-position.js";
import { easeInOutQuad } from "../poi-group/animation-utils.js";
import "../building-blocks/poi/poi-base.js";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result) __defProp(target, key, result);
  return result;
};
const EXIT_DELAY_MS_VAR = "--obc-poi-layer-exit-delay-ms";
const GROUP_REMOVAL_DELAY_MS_VAR = "--obc-poi-layer-group-removal-delay-ms";
const EXIT_LOCK_DURATION_MS_VAR = "--obc-poi-layer-exit-lock-duration-ms";
const POI_TOUCH_TARGET_VAR = "--maneuvering-components-poi-button-touch-target";
const POI_VISUAL_TARGET_VAR = "--maneuvering-components-poi-button-visual-target-round";
const POI_VISUAL_TARGET_OVERLAP_VAR = "--maneuvering-components-poi-button-visual-target-round-overlap";
const POI_LARGE_VISUAL_TARGET_VAR = "--maneuvering-components-poi-button-large-visual-target-round";
const POI_LARGE_VISUAL_TARGET_OVERLAP_VAR = "--maneuvering-components-poi-button-large-visual-target-round-overlap";
const POI_CROSSING_MIN_GAP_VAR = "--obc-poi-layer-crossing-min-gap";
var OverlapMode = /* @__PURE__ */ ((OverlapMode2) => {
  OverlapMode2["Grouping"] = "grouping";
  OverlapMode2["Crossing"] = "crossing";
  return OverlapMode2;
})(OverlapMode || {});
let ObcPoiLayer = class extends LitElement {
  constructor() {
    super(...arguments);
    this.label = "";
    this.debug = false;
    this.overlapMode = "grouping";
    this.isSelected = false;
    this.joinWhileExpanded = false;
    this.internalSwapping = false;
    this.lastHeight = 0;
    this.persistedHeight = 0;
    this.isGrouping = false;
    this.targetObservers = /* @__PURE__ */ new Map();
    this.targetSizeElements = /* @__PURE__ */ new Map();
    this.groupingRaf = 0;
    this.heightRaf = 0;
    this.groupRemovalTimers = /* @__PURE__ */ new WeakMap();
    this.exitLockTimers = /* @__PURE__ */ new Map();
    this.autoGroupCollapseTimeout = 0;
    this.crossingModeRaf = 0;
    this.cachedCrossingTargets = [];
    this.crossingTargetsDirty = false;
    this.crossingOrder = [];
    this.crossingLastEffectiveX = /* @__PURE__ */ new Map();
    this.previousPositions = /* @__PURE__ */ new Map();
    this.lastOffsets = /* @__PURE__ */ new Map();
    this.handleSlotChange = () => {
      this.updateTargetObservers();
      this.scheduleGrouping();
      this.scheduleLayerHeightUpdate();
    };
    this.handleCollapseFinished = () => {
      this.scheduleGrouping();
    };
    this.handlePoiDataLayoutChange = () => {
      this.scheduleGrouping();
      this.scheduleLayerHeightUpdate();
    };
    this.handleGroupExpand = (event) => {
      const group = event.target;
      if (!group?.tagName?.toLowerCase().includes("group")) return;
      if (group.hasAttribute("data-exiting")) return;
      const targets = this.getAllTargets();
      const groupedTargets = new Set(this.getGroupTargets(group));
      if (groupedTargets.size === 0) return;
      if (event.detail.expand) {
        targets.forEach((target) => {
          if (!groupedTargets.has(target)) {
            const nextValue = this.resolveTargetValue(target, true);
            target.value = nextValue;
            if (nextValue === ObcPoiValue.Overlapped) {
              this.applyStandaloneVisualState(target, true);
            } else {
              this.clearStandaloneVisualState(target);
            }
          }
        });
      }
    };
    this.buttonOffsetXResetRaf = /* @__PURE__ */ new Map();
  }
  connectedCallback() {
    super.connectedCallback();
    if (!this.hasUpdated) return;
    this.setupResizeObserver();
    this.setupTargetResizeObserver();
    this.setupLayerMutationObserver();
    this.updateTargetObservers();
    this.scheduleGrouping();
    this.scheduleLayerHeightUpdate();
    this.addLayerEventListeners();
    const slot = this.shadowRoot?.querySelector("slot");
    slot?.addEventListener("slotchange", this.handleSlotChange);
  }
  firstUpdated() {
    this.crossingTargetsDirty = true;
    this.setupResizeObserver();
    this.setupTargetResizeObserver();
    this.setupLayerMutationObserver();
    this.updateTargetObservers();
    this.scheduleGrouping();
    this.scheduleLayerHeightUpdate();
    const slot = this.shadowRoot?.querySelector("slot");
    slot?.addEventListener("slotchange", this.handleSlotChange);
    requestAnimationFrame(() => {
      this.updateTargetObservers();
      this.scheduleLayerHeightUpdate();
    });
    this.addLayerEventListeners();
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this.removeLayerEventListeners();
    const slot = this.shadowRoot?.querySelector("slot");
    slot?.removeEventListener("slotchange", this.handleSlotChange);
    this.resizeObserver?.disconnect();
    this.targetResizeObserver?.disconnect();
    this.layerMutationObserver?.disconnect();
    this.targetObservers.forEach((observer) => observer.disconnect());
    this.targetObservers.clear();
    this.targetSizeElements.clear();
    if (this.groupingRaf) {
      cancelAnimationFrame(this.groupingRaf);
      this.groupingRaf = 0;
    }
    if (this.crossingModeRaf) {
      cancelAnimationFrame(this.crossingModeRaf);
      this.crossingModeRaf = 0;
    }
    this.previousPositions.clear();
    if (this.heightRaf) {
      cancelAnimationFrame(this.heightRaf);
      this.heightRaf = 0;
    }
    this.exitLockTimers.forEach((timerId) => window.clearTimeout(timerId));
    this.exitLockTimers.clear();
    if (this.autoGroupCollapseTimeout) {
      window.clearTimeout(this.autoGroupCollapseTimeout);
      this.autoGroupCollapseTimeout = 0;
    }
    this.buttonOffsetXResetRaf.forEach((rafId) => cancelAnimationFrame(rafId));
    this.buttonOffsetXResetRaf.clear();
    this.lastOffsets.clear();
    this.crossingLastEffectiveX.clear();
  }
  addLayerEventListeners() {
    this.addEventListener(
      "obc-poi-data-layout-change",
      this.handlePoiDataLayoutChange
    );
    this.addEventListener("expand", this.handleGroupExpand);
    this.addEventListener(
      "collapse-finished",
      this.handleCollapseFinished
    );
  }
  removeLayerEventListeners() {
    this.removeEventListener(
      "obc-poi-data-layout-change",
      this.handlePoiDataLayoutChange
    );
    this.removeEventListener("expand", this.handleGroupExpand);
    this.removeEventListener(
      "collapse-finished",
      this.handleCollapseFinished
    );
  }
  setupResizeObserver() {
    if (typeof ResizeObserver === "undefined") return;
    this.resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) {
        this.updateLayerHeight(entry.contentRect.height);
      }
    });
    if (this.wrapper) {
      this.resizeObserver.observe(this.wrapper);
      this.updateLayerHeight(this.wrapper.getBoundingClientRect().height);
    }
  }
  setupTargetResizeObserver() {
    if (typeof ResizeObserver === "undefined") return;
    if (this.targetResizeObserver) return;
    this.targetResizeObserver = new ResizeObserver(
      () => this.scheduleLayerHeightUpdate()
    );
  }
  scheduleLayerHeightUpdate() {
    if (this.heightRaf) return;
    this.heightRaf = requestAnimationFrame(() => {
      this.heightRaf = 0;
      this.syncLayerHeight();
    });
  }
  syncLayerHeight() {
    if (!this.isConnected) return;
    const minHeight = this.getLayerMinHeight();
    const targets = this.getAllTargets();
    if (targets.length === 0) {
      const nextHeight2 = Math.max(this.persistedHeight, minHeight);
      this.style.setProperty("--obc-poi-layer-height", `${nextHeight2}px`);
      this.updateLayerHeight(nextHeight2);
      return;
    }
    const rects = /* @__PURE__ */ new Map();
    targets.forEach((target) => rects.set(target, this.getTargetRect(target)));
    let maxHeight = 0;
    rects.forEach((rect) => {
      const height = rect?.height ?? 0;
      if (Number.isFinite(height)) {
        maxHeight = Math.max(maxHeight, height);
      }
    });
    const nextHeight = Math.max(maxHeight, minHeight, this.persistedHeight);
    if (nextHeight <= 0) {
      this.style.setProperty("--obc-poi-layer-height", "0px");
      this.updateLayerHeight(0);
      return;
    }
    const roundedHeight = Math.round(nextHeight);
    this.persistedHeight = Math.max(this.persistedHeight, roundedHeight);
    this.style.setProperty("--obc-poi-layer-height", `${roundedHeight}px`);
    this.updateLayerHeight(roundedHeight);
  }
  getLayerMinHeight() {
    const minHeightRaw = getComputedStyle(this).minHeight;
    const minHeight = Number.parseFloat(minHeightRaw);
    return Number.isFinite(minHeight) ? minHeight : 0;
  }
  updateLayerHeight(nextHeight) {
    const roundedHeight = Math.round(nextHeight);
    if (roundedHeight === this.lastHeight) return;
    this.lastHeight = roundedHeight;
    this.dispatchEvent(
      new CustomEvent("layer-resize", {
        detail: {
          height: roundedHeight,
          label: this.label
        },
        bubbles: true,
        composed: true
      })
    );
  }
  updateTargetObservers() {
    const targets = this.getAllTargets();
    const targetSet = new Set(targets);
    this.targetObservers.forEach((observer, target) => {
      if (!targetSet.has(target)) {
        observer.disconnect();
        this.targetObservers.delete(target);
      }
    });
    targets.forEach((target) => {
      if (this.targetObservers.has(target)) return;
      const observer = new MutationObserver(() => {
        this.scheduleGrouping();
        this.scheduleLayerHeightUpdate();
      });
      observer.observe(target, {
        attributes: true,
        attributeFilter: ["style", "y", "button-y"]
      });
      this.targetObservers.set(target, observer);
    });
    this.updateTargetSizeObservers(targets, targetSet);
  }
  updateTargetSizeObservers(targets, targetSet) {
    if (!this.targetResizeObserver) return;
    this.targetSizeElements.forEach((element, target) => {
      if (!targetSet.has(target) || !element.isConnected) {
        this.targetResizeObserver?.unobserve(element);
        this.targetSizeElements.delete(target);
      }
    });
    targets.forEach((target) => {
      const sizeElement = this.getTargetSizeElement(target);
      if (!sizeElement) return;
      const existing = this.targetSizeElements.get(target);
      if (existing === sizeElement) return;
      if (existing) {
        this.targetResizeObserver?.unobserve(existing);
      }
      this.targetResizeObserver?.observe(sizeElement);
      this.targetSizeElements.set(target, sizeElement);
    });
  }
  getTargetSizeElement(target) {
    return target.getVisualElement(PoiDataVisualRectPreference.Size);
  }
  isPoiLayerRelevantNode(node) {
    if (isPoi(node) || node.tagName.toLowerCase() === "obc-poi-group")
      return true;
    return !!node.querySelector(`[${POI_ATTR}], obc-poi-group`);
  }
  setupLayerMutationObserver() {
    this.layerMutationObserver?.disconnect();
    this.layerMutationObserver = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type !== "childList") continue;
        const nodes = [...mutation.addedNodes, ...mutation.removedNodes];
        for (const node of nodes) {
          if (!(node instanceof HTMLElement)) continue;
          if (this.isPoiLayerRelevantNode(node)) {
            this.updateTargetObservers();
            this.scheduleGrouping();
            this.scheduleLayerHeightUpdate();
            this.crossingTargetsDirty = true;
            return;
          }
        }
      }
    });
    this.layerMutationObserver.observe(this, { childList: true, subtree: true });
  }
  requestGroupingUpdate() {
    this.scheduleGrouping();
    this.scheduleLayerHeightUpdate();
  }
  scheduleGrouping() {
    if (this.overlapMode === "crossing") {
      this.scheduleCrossingMode();
      return;
    }
    if (this.groupingRaf) return;
    this.groupingRaf = requestAnimationFrame(() => {
      this.groupingRaf = 0;
      this.updateGrouping();
    });
  }
  scheduleCrossingMode() {
    if (this.crossingModeRaf) return;
    this.crossingModeRaf = requestAnimationFrame(() => {
      try {
        this.crossingModeRaf = 0;
        const shouldContinue = this.updateCrossingMode();
        if (this.overlapMode === "crossing" && this.isConnected && shouldContinue) {
          this.scheduleCrossingMode();
        }
      } catch (error) {
        console.error("[poi-layer] Error in crossing mode:", error);
        this.crossingModeRaf = 0;
      }
    });
  }
  updateCrossingMode() {
    if (this.crossingTargetsDirty) {
      this.cachedCrossingTargets = this.getAllTargets();
      this.crossingTargetsDirty = false;
    }
    const targets = this.cachedCrossingTargets;
    const buttonWidth = this.getTouchTargetSize();
    const minGap = this.getCssVarAsNumber(
      POI_CROSSING_MIN_GAP_VAR,
      buttonWidth + 4
    );
    const next = updateCrossingModeState({
      targets,
      buttonWidth,
      minGap,
      previousPositions: this.previousPositions,
      lastOffsets: this.lastOffsets,
      crossingOrder: this.crossingOrder,
      crossingLastEffectiveX: this.crossingLastEffectiveX
    });
    this.previousPositions = next.previousPositions;
    this.crossingOrder = next.crossingOrder;
    return next.shouldContinue;
  }
  toggleGroupLayerHook(group, hasTargets) {
    if (hasTargets) {
      group.setAttribute(ObcPoiLayer.GROUP_LAYER_HOOK_ATTR, "");
    } else {
      group.removeAttribute(ObcPoiLayer.GROUP_LAYER_HOOK_ATTR);
    }
  }
  updateGrouping() {
    if (this.isGrouping) return;
    this.isGrouping = true;
    try {
      const manualGroups = Array.from(
        this.querySelectorAll("obc-poi-group")
      ).filter((group) => !group.hasAttribute("data-auto-group"));
      const manualGroupedTargets = /* @__PURE__ */ new Set();
      manualGroups.forEach((group) => {
        const groupTargets = this.getGroupTargets(group);
        this.toggleGroupLayerHook(group, groupTargets.length > 0);
        groupTargets.forEach((target) => manualGroupedTargets.add(target));
      });
      if (manualGroups.length > 0) {
        const anyExpanded = manualGroups.some(
          (group) => group.expand === true || group.collapsing === true
        );
        if (anyExpanded) {
          return;
        }
      }
      const targets = this.getAllTargets().filter(
        (target) => !manualGroupedTargets.has(target)
      );
      const layerRect = this.getBoundingClientRect();
      const enterRaw = getComputedStyle(this).getPropertyValue(
        "--obc-poi-layer-overlap-enter"
      );
      const exitRaw = getComputedStyle(this).getPropertyValue(
        "--obc-poi-layer-overlap-exit"
      );
      const preRaw = getComputedStyle(this).getPropertyValue(
        "--obc-poi-layer-overlap-pre"
      );
      const behindRaw = getComputedStyle(this).getPropertyValue(
        "--obc-poi-layer-overlap-behind"
      );
      const enterThreshold = Number.parseFloat(enterRaw) || 0;
      const exitThreshold = Number.parseFloat(exitRaw) || Math.max(enterThreshold + 8, 8);
      const preThreshold = Number.parseFloat(preRaw) || enterThreshold;
      const behindThreshold = Number.parseFloat(behindRaw) || enterThreshold;
      const currentGroupByTarget = /* @__PURE__ */ new Map();
      targets.forEach((target) => {
        const parent = target.parentElement;
        if (parent?.tagName.toLowerCase() === "obc-poi-group") {
          currentGroupByTarget.set(target, parent);
        }
      });
      const rects = /* @__PURE__ */ new Map();
      targets.forEach((target) => {
        rects.set(target, this.getTargetRectForGrouping(target, layerRect));
      });
      const thresholds = {
        enterThreshold,
        exitThreshold,
        preThreshold,
        behindThreshold
      };
      const { adjacency, behindAdjacency, preGrouped } = buildAdjacencyMaps(
        targets,
        rects,
        thresholds,
        currentGroupByTarget
      );
      const clusters = buildClusters(targets, adjacency);
      const behindClusters = buildClusters(targets, behindAdjacency);
      const existingGroups = Array.from(
        this.querySelectorAll("obc-poi-group[data-auto-group]")
      );
      const frontTargets = /* @__PURE__ */ new Set();
      clusters.forEach((cluster) => {
        const front = this.getFrontTarget(cluster, rects);
        if (front) frontTargets.add(front);
      });
      const behindTargets = /* @__PURE__ */ new Set();
      behindClusters.forEach((cluster) => {
        const behind = this.getShortestTarget(cluster, rects);
        if (behind) behindTargets.add(behind);
      });
      const expandedAutoGroup = existingGroups.find(
        (group) => group.expand === true || group.collapsing === true
      );
      if (expandedAutoGroup) {
        if (this.joinWhileExpanded) {
          this.tryJoinExpandedGroup(
            expandedAutoGroup,
            targets,
            rects,
            enterThreshold
          );
        }
        return;
      }
      const remainingClusters = [...clusters];
      const keptGroups = [];
      existingGroups.forEach((group) => {
        const children = Array.from(group.children).filter(
          (child) => isPoi(child)
        );
        const matchIndex = remainingClusters.findIndex(
          (cluster) => cluster.length === children.length && cluster.every((target) => children.includes(target))
        );
        if (matchIndex >= 0) {
          keptGroups.push(group);
          group.removeAttribute("data-exiting");
          group.setAttribute("data-visible", "true");
          remainingClusters.splice(matchIndex, 1);
        } else {
          const front = this.getFrontTarget(children, rects);
          children.forEach((child) => {
            if (front && child === front) {
              child.setAttribute("data-front", "true");
              child.setAttribute("data-front-exit", "true");
            } else {
              child.removeAttribute("data-front");
            }
          });
          children.forEach((child) => {
            if (!front || child !== front) {
              child.setAttribute("data-exiting", "true");
              this.startExitLock(child);
            } else {
              child.removeAttribute("data-exiting");
              child.removeAttribute("data-exit-lock");
            }
            child.removeAttribute("data-grouped");
            this.resetTarget(child);
          });
          group.removeAttribute("data-visible");
          group.setAttribute("data-exiting", "true");
          children.forEach((child) => this.appendChild(child));
          children.forEach((child) => {
            if (!front || child !== front) {
              child.getBoundingClientRect();
            }
          });
          const exitDelay = this.getCssVarAsNumber(EXIT_DELAY_MS_VAR, 140);
          window.setTimeout(() => {
            children.forEach((child) => {
              if (!front || child !== front) {
                child.removeAttribute("data-exiting");
              }
            });
          }, exitDelay);
          requestAnimationFrame(() => {
            this.scheduleGroupRemoval(group);
          });
        }
      });
      remainingClusters.forEach((cluster) => {
        const group = document.createElement("obc-poi-group");
        group.setAttribute("data-auto-group", "true");
        group.setAttribute("data-position-mode", "bottom");
        group.setAttribute("data-visible", "true");
        group.internalSwapping = !!this.internalSwapping;
        group.setAttribute(
          "positionVertical",
          `${this.getGroupPositionVertical(cluster, rects, layerRect, group)}px`
        );
        cluster.forEach((target) => {
          target.removeAttribute("data-grouped");
          group.appendChild(target);
        });
        this.appendChild(group);
        requestAnimationFrame(() => {
          cluster.forEach(
            (target) => target.setAttribute("data-grouped", "true")
          );
        });
        keptGroups.push(group);
      });
      const groupedTargets = /* @__PURE__ */ new Set();
      keptGroups.forEach((group) => {
        Array.from(group.children).forEach((child) => {
          if (isPoi(child)) groupedTargets.add(child);
        });
      });
      targets.forEach((target) => {
        if (!groupedTargets.has(target)) {
          const exitLocked = target.hasAttribute("data-exit-lock");
          target.removeAttribute("data-grouped");
          target.removeAttribute("data-joined-expanded");
          if (target.hasAttribute("data-front-exit")) {
            target.setAttribute("data-front", "true");
            target.removeAttribute("data-pregrouped");
          } else if (frontTargets.has(target)) {
            target.setAttribute("data-front", "true");
            target.removeAttribute("data-pregrouped");
          } else if (preGrouped.has(target) && !exitLocked) {
            target.removeAttribute("data-front");
            target.setAttribute("data-pregrouped", "true");
          } else {
            target.removeAttribute("data-front");
            target.removeAttribute("data-pregrouped");
          }
          if (!exitLocked && behindTargets.has(target) && !frontTargets.has(target)) {
            target.setAttribute("data-behind", "true");
          } else {
            target.removeAttribute("data-behind");
          }
          if (exitLocked) {
            target.removeAttribute("data-pregrouped");
            target.removeAttribute("data-behind");
          }
          const isOverlapState = target.hasAttribute("data-behind");
          const nextValue = this.resolveTargetValue(target, isOverlapState);
          target.value = nextValue;
          if (nextValue === ObcPoiValue.Overlapped) {
            this.applyStandaloneVisualState(target, true);
          } else {
            this.clearStandaloneVisualState(target);
          }
          this.resetTarget(target);
        } else {
          target.removeAttribute("data-behind");
          this.clearStandaloneVisualState(target);
        }
      });
      this.refreshGroupPositions(layerRect, rects);
      requestAnimationFrame(() => {
        targets.forEach((target) => target.removeAttribute("data-front-exit"));
      });
      this.scheduleLayerHeightUpdate();
    } finally {
      this.isGrouping = false;
    }
  }
  tryJoinExpandedGroup(group, targets, rects, enterThreshold) {
    const groupTargets = this.getGroupTargets(group);
    if (groupTargets.length === 0) return;
    const groupTargetSet = new Set(groupTargets);
    const candidates = targets.filter(
      (target) => !groupTargetSet.has(target) && target.parentElement?.tagName.toLowerCase() !== "obc-poi-group"
    );
    if (candidates.length === 0) return;
    const useButtonRects = group.expand === true || group.collapsing === true;
    const groupCenters = groupTargets.map(
      (target) => useButtonRects ? this.getTargetRect(target) : rects.get(target)
    ).filter((rect) => !!rect).map((rect) => rect.left + rect.width / 2);
    if (groupCenters.length === 0) return;
    const leftMost = Math.min(...groupCenters);
    const rightMost = Math.max(...groupCenters);
    const groupCenter = (leftMost + rightMost) / 2;
    let bestCandidate = null;
    let bestGap = Number.POSITIVE_INFINITY;
    for (const candidate of candidates) {
      const candidateRect2 = useButtonRects ? this.getTargetRect(candidate) : rects.get(candidate);
      if (!candidateRect2) continue;
      for (const member of groupTargets) {
        const memberRect = useButtonRects ? this.getTargetRect(member) : rects.get(member);
        if (!memberRect) continue;
        const overlapHeight = Math.min(candidateRect2.bottom, memberRect.bottom) - Math.max(candidateRect2.top, memberRect.top);
        if (overlapHeight <= 0) continue;
        const gap = Math.max(
          0,
          Math.max(candidateRect2.left, memberRect.left) - Math.min(candidateRect2.right, memberRect.right)
        );
        if (gap <= enterThreshold && gap < bestGap) {
          bestGap = gap;
          bestCandidate = candidate;
        }
      }
    }
    if (!bestCandidate) return;
    bestCandidate.setAttribute("data-joined-expanded", "true");
    const candidateRect = rects.get(bestCandidate);
    const candidateCenter = candidateRect?.left !== void 0 ? candidateRect.left + candidateRect.width / 2 : 0;
    const insertBefore = candidateCenter < groupCenter;
    if (insertBefore) {
      group.insertBefore(bestCandidate, groupTargets[0] ?? null);
    } else {
      group.appendChild(bestCandidate);
    }
    bestCandidate.setAttribute("data-grouped", "true");
    bestCandidate.removeAttribute("data-behind");
    bestCandidate.removeAttribute("data-pregrouped");
    bestCandidate.value = this.resolveTargetValue(bestCandidate, false);
    this.clearStandaloneVisualState(bestCandidate);
    const touchRaw = getComputedStyle(group).getPropertyValue(
      "--maneuvering-components-poi-button-touch-target"
    );
    const touchSize = Number.parseFloat(touchRaw) || 0;
    if (touchSize > 0) {
      const touchTarget = `${touchSize}px`;
      bestCandidate.style.width = touchTarget;
      bestCandidate.style.minWidth = touchTarget;
      bestCandidate.style.height = touchTarget;
    }
    group.refreshExpandedLayout?.(true);
  }
  applyStandaloneVisualState(target, overlap) {
    const isEnhanced = target.buttonType === ObcPoiButtonType.Enhanced;
    const size = this.getVisualTargetSize(isEnhanced, overlap);
    target.style.setProperty("--poi-size", `${size}px`);
    target.style.setProperty(
      "--obc-poi-target-icon-opacity",
      overlap ? "0" : "1"
    );
    target.style.setProperty("--obc-poi-overlap", overlap ? "1" : "0");
    target.style.setProperty(
      "--obc-poi-overlap-elements-opacity",
      overlap ? "0" : "1"
    );
    target.style.setProperty("--obc-poi-label-opacity", overlap ? "0" : "1");
    target.style.setProperty(
      "--obc-poi-label-visibility",
      overlap ? "hidden" : "visible"
    );
    target.style.setProperty(
      "--obc-poi-overlap-pointer-events",
      overlap ? "none" : "auto"
    );
  }
  resolveTargetValue(target, overlap) {
    if (overlap) {
      return ObcPoiValue.Overlapped;
    }
    if (target.selected) {
      return ObcPoiValue.Checked;
    }
    return ObcPoiValue.Unchecked;
  }
  clearStandaloneVisualState(target) {
    target.style.removeProperty("--poi-size");
    target.style.removeProperty("--obc-poi-target-icon-opacity");
    target.style.removeProperty("--obc-poi-overlap");
    target.style.removeProperty("--obc-poi-overlap-elements-opacity");
    target.style.removeProperty("--obc-poi-label-opacity");
    target.style.removeProperty("--obc-poi-label-visibility");
    target.style.removeProperty("--obc-poi-overlap-pointer-events");
  }
  refreshGroupPositions(layerRect, rects) {
    const groups = Array.from(
      this.querySelectorAll("obc-poi-group")
    );
    groups.forEach((group) => {
      const children = Array.from(group.children).filter(
        (child) => isPoi(child)
      );
      this.toggleGroupLayerHook(group, children.length > 0);
      const hasPositionAttr = group.hasAttribute("positionvertical") || group.hasAttribute("positionVertical");
      if (!group.hasAttribute("data-auto-group") && !group.hasAttribute("data-position-mode")) {
        group.setAttribute("data-position-mode", "bottom");
      }
      const shouldSetPosition = group.hasAttribute("data-auto-group") || !hasPositionAttr;
      if (group.hasAttribute("data-auto-group")) {
        group.internalSwapping = !!this.internalSwapping;
      }
      if (children.length > 0 && shouldSetPosition) {
        const layerBounds = layerRect ?? this.getBoundingClientRect();
        const rectMap = rects ?? new Map(
          children.map((child) => [
            child,
            this.getTargetRectForGrouping(child, layerBounds)
          ])
        );
        group.setAttribute(
          "positionVertical",
          `${this.getGroupPositionVertical(children, rectMap, layerBounds, group)}px`
        );
      }
      group.updatePosition?.();
    });
  }
  getGroupPositionVertical(targets, rects, layerRect, group) {
    let maxBottom = Number.NEGATIVE_INFINITY;
    targets.forEach((target) => {
      const rect = rects.get(target) ?? target.getBoundingClientRect();
      maxBottom = Math.max(maxBottom, rect.bottom);
    });
    const baseBottom = maxBottom - layerRect.top;
    const isAutoGroup = group?.hasAttribute("data-auto-group") ?? false;
    const offsetRaw = getComputedStyle(this).getPropertyValue(
      "--obc-poi-layer-auto-group-offset-y"
    );
    let offset = Number.parseFloat(offsetRaw) || 0;
    if (isAutoGroup && this.closest("obc-poi-layer-stack")) {
      offset = 0;
    }
    return Math.round(baseBottom + offset);
  }
  resetTarget(target) {
    if (typeof target.targetOffsetX === "number") {
      target.targetOffsetX = 0;
    }
    this.animateButtonOffsetXToZero(target);
    target.style.removeProperty("--obc-poi-target-offset-x");
    target.style.removeProperty("position");
    target.style.removeProperty("width");
    target.style.removeProperty("min-width");
    target.style.removeProperty("height");
    target.style.removeProperty("transform");
    target.style.removeProperty("--obc-poi-group-overlap-height");
    target.style.removeProperty("--obc-poi-group-overlap-shift");
  }
  animateButtonOffsetXToZero(target) {
    const start = target.buttonOffsetX;
    if (!Number.isFinite(start) || Math.abs(start) < 0.5) {
      target.buttonOffsetX = 0;
      return;
    }
    const existing = this.buttonOffsetXResetRaf.get(target);
    if (existing) {
      cancelAnimationFrame(existing);
    }
    const duration = 100;
    const startTime = performance.now();
    const step = (now) => {
      try {
        if (!target.isConnected) {
          this.buttonOffsetXResetRaf.delete(target);
          return;
        }
        const t = Math.min((now - startTime) / duration, 1);
        const eased = easeInOutQuad(t);
        target.buttonOffsetX = start + (0 - start) * eased;
        if (t < 1) {
          this.buttonOffsetXResetRaf.set(target, requestAnimationFrame(step));
        } else {
          this.buttonOffsetXResetRaf.delete(target);
        }
      } catch (error) {
        console.error("[poi-layer] Error in button offset reset:", error);
        this.buttonOffsetXResetRaf.delete(target);
      }
    };
    this.buttonOffsetXResetRaf.set(target, requestAnimationFrame(step));
  }
  scheduleGroupRemoval(group) {
    const existing = this.groupRemovalTimers.get(group);
    if (existing) {
      window.clearTimeout(existing);
    }
    group.setAttribute("data-exiting", "true");
    const removalDelay = this.getCssVarAsNumber(
      GROUP_REMOVAL_DELAY_MS_VAR,
      250
    );
    const timeoutId = window.setTimeout(() => {
      group.remove();
      this.groupRemovalTimers.delete(group);
    }, removalDelay);
    this.groupRemovalTimers.set(group, timeoutId);
  }
  startExitLock(target) {
    target.setAttribute("data-exit-lock", "true");
    const existing = this.exitLockTimers.get(target);
    if (existing) window.clearTimeout(existing);
    const lockDuration = this.getCssVarAsNumber(EXIT_LOCK_DURATION_MS_VAR, 500);
    const timeoutId = window.setTimeout(() => {
      target.removeAttribute("data-exit-lock");
      this.exitLockTimers.delete(target);
    }, lockDuration);
    this.exitLockTimers.set(target, timeoutId);
  }
  getFrontTarget(targets, rects) {
    if (targets.length === 0) return null;
    let front = targets[0];
    let maxHeight = this.getTargetHeight(front, rects);
    targets.forEach((target) => {
      const height = this.getTargetHeight(target, rects);
      if (height > maxHeight) {
        maxHeight = height;
        front = target;
      }
    });
    return front;
  }
  getTargetRect(target) {
    if (isPoi(target)) {
      return target.getVisualRect(PoiDataVisualRectPreference.Largest);
    }
    return target.getBoundingClientRect();
  }
  getTargetRectForGrouping(target, layerRect) {
    const rect = this.getTargetRect(target);
    const leftValue = getEffectivePoiX(target);
    if (!Number.isFinite(leftValue)) return rect;
    const width = rect.width || 0;
    const height = rect.height || 0;
    const left = layerRect.left + leftValue - width / 2;
    const top = layerRect.bottom - height;
    return new DOMRect(left, top, width, height);
  }
  getTargetHeight(target, rects) {
    if (Number.isFinite(target.y ?? NaN)) {
      return target.y ?? 0;
    }
    const yAttr = target.getAttribute("y");
    const yValue = Number.parseFloat(yAttr ?? "");
    if (!Number.isNaN(yValue)) return yValue;
    if (typeof target.buttonY === "number" && Number.isFinite(target.buttonY)) {
      return target.buttonY;
    }
    const buttonYAttr = target.getAttribute("button-y");
    const buttonYValue = Number.parseFloat(buttonYAttr ?? "");
    if (!Number.isNaN(buttonYValue)) return buttonYValue;
    const rect = rects?.get(target) ?? this.getTargetRect(target);
    return rect.height;
  }
  getShortestTarget(targets, rects) {
    if (targets.length === 0) return null;
    let shortest = targets[0];
    let minHeight = this.getTargetHeight(shortest, rects);
    targets.forEach((target) => {
      const height = this.getTargetHeight(target, rects);
      if (height < minHeight) {
        minHeight = height;
        shortest = target;
      }
    });
    return shortest;
  }
  getAllTargets() {
    return Array.from(this.querySelectorAll(`[${POI_ATTR}]`)).filter(
      (node) => isPoi(node)
    );
  }
  getGroupTargets(group) {
    return Array.from(group.querySelectorAll(`[${POI_ATTR}]`)).filter(
      (node) => isPoi(node)
    );
  }
  render() {
    return html`
      <div class="wrapper">
        ${this.debug ? html`<span class="debug-label">${this.label || "Layer"}</span>` : nothing}
        <slot></slot>
      </div>
    `;
  }
  getCssVarAsNumber(varName, fallback) {
    const raw = getComputedStyle(this).getPropertyValue(varName).trim();
    const parsed = Number.parseFloat(raw);
    return Number.isFinite(parsed) ? parsed : fallback;
  }
  getTouchTargetSize() {
    return this.getCssVarAsNumber(POI_TOUCH_TARGET_VAR, 48);
  }
  getVisualTargetSize(isEnhanced, isOverlap) {
    if (isEnhanced) {
      return isOverlap ? this.getCssVarAsNumber(POI_LARGE_VISUAL_TARGET_OVERLAP_VAR, 36) : this.getCssVarAsNumber(POI_LARGE_VISUAL_TARGET_VAR, 52);
    }
    return isOverlap ? this.getCssVarAsNumber(POI_VISUAL_TARGET_OVERLAP_VAR, 32) : this.getCssVarAsNumber(POI_VISUAL_TARGET_VAR, 36);
  }
};
ObcPoiLayer.GROUP_LAYER_HOOK_ATTR = "data-in-poi-layer";
ObcPoiLayer.styles = unsafeCSS(componentStyle);
__decorateClass([
  property({ type: String })
], ObcPoiLayer.prototype, "label", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcPoiLayer.prototype, "debug", 2);
__decorateClass([
  property({ type: String })
], ObcPoiLayer.prototype, "overlapMode", 2);
__decorateClass([
  property({ type: Boolean, reflect: true, attribute: "is-selected" })
], ObcPoiLayer.prototype, "isSelected", 2);
__decorateClass([
  property({ type: Boolean, attribute: "join-while-expanded" })
], ObcPoiLayer.prototype, "joinWhileExpanded", 2);
__decorateClass([
  property({ type: Boolean, attribute: "internal-swapping" })
], ObcPoiLayer.prototype, "internalSwapping", 2);
__decorateClass([
  query(".wrapper")
], ObcPoiLayer.prototype, "wrapper", 2);
ObcPoiLayer = __decorateClass([
  customElement("obc-poi-layer")
], ObcPoiLayer);
export {
  ObcPoiLayer,
  OverlapMode
};
//# sourceMappingURL=poi-layer.js.map
