var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.ts
var useFloorMapTransformMetrics_exports = {};
__export(useFloorMapTransformMetrics_exports, {
  useFloorMapTransformMetrics: () => useFloorMapTransformMetrics
});
module.exports = __toCommonJS(useFloorMapTransformMetrics_exports);
var import_react = require("react");
var import_layoutMeasurements = require("../utils/layoutMeasurements");
var DEFAULT_BOUNDING_PADDING = 56;
var VIEWPORT_TOP_LEFT_MARGIN = 16;
function useFloorMapTransformMetrics(params) {
  const {
    items,
    cellSize,
    itemGap,
    effectiveItemUnit,
    isFloorMapView,
    mode,
    zoom,
    transformRef,
    contentOffsetRef,
    boundingPadding: boundingPaddingProp,
    frameResetKey
  } = params;
  const padSingle = boundingPaddingProp ?? DEFAULT_BOUNDING_PADDING;
  const containerRef = (0, import_react.useRef)(null);
  const mapAreaRef = (0, import_react.useRef)(null);
  const [viewportSize, setViewportSize] = (0, import_react.useState)({ width: 0, height: 0 });
  (0, import_react.useEffect)(() => {
    const el = containerRef.current;
    if (!el) return;
    const ro = new ResizeObserver(() => {
      setViewportSize({ width: el.clientWidth, height: el.clientHeight });
    });
    ro.observe(el);
    setViewportSize({ width: el.clientWidth, height: el.clientHeight });
    return () => ro.disconnect();
  }, []);
  const [mapAreaSize, setMapAreaSize] = (0, import_react.useState)({ width: 0, height: 0 });
  (0, import_react.useEffect)(() => {
    const el = mapAreaRef.current;
    if (!el) return;
    const ro = new ResizeObserver(() => {
      setMapAreaSize({ width: el.clientWidth, height: el.clientHeight });
    });
    ro.observe(el);
    setMapAreaSize({ width: el.clientWidth, height: el.clientHeight });
    return () => ro.disconnect();
  }, []);
  const autoFitOnMount = zoom.autoFitOnMount !== false;
  const zoomConfig = (0, import_react.useMemo)(
    () => ({
      initialScale: zoom.defaultScale ?? 1,
      minScale: zoom.min ?? 0.5,
      maxScale: zoom.max ?? 2,
      step: zoom.step ?? 0.1
    }),
    [zoom.defaultScale, zoom.min, zoom.max, zoom.step]
  );
  const [scale, setScale] = (0, import_react.useState)(zoomConfig.initialScale);
  const [isFullscreen, setIsFullscreen] = (0, import_react.useState)(false);
  const {
    contentWidth,
    contentHeight,
    contentOffsetX,
    contentOffsetY,
    alignPadSingle
  } = (0, import_react.useMemo)(() => {
    const fromItems = (0, import_layoutMeasurements.getContentSize)(
      items,
      cellSize,
      itemGap,
      effectiveItemUnit
    );
    const pad = padSingle * 2;
    const zeroOffset = { contentOffsetX: 0, contentOffsetY: 0 };
    const useBoundingBox = isFloorMapView && effectiveItemUnit === "pixel" && items.length > 0;
    const box = useBoundingBox ? (0, import_layoutMeasurements.getPixelBoundingBox)(items, cellSize) : null;
    let padded;
    let alignPad = null;
    if (box) {
      const w = box.maxRight - box.minLeft + pad;
      const h = box.maxBottom - box.minTop + pad;
      padded = {
        contentWidth: w,
        contentHeight: h,
        contentOffsetX: padSingle - box.minLeft,
        contentOffsetY: padSingle - box.minTop
      };
      alignPad = padSingle;
    } else {
      padded = {
        contentWidth: fromItems.contentWidth + pad,
        contentHeight: fromItems.contentHeight + pad,
        ...zeroOffset
      };
    }
    let result = { ...padded, alignPadSingle: alignPad };
    if (!isFloorMapView || effectiveItemUnit !== "pixel") return result;
    const vw = mapAreaSize.width > 0 ? mapAreaSize.width : viewportSize.width;
    const vh = mapAreaSize.height > 0 ? mapAreaSize.height : viewportSize.height;
    if (vw <= 0 || vh <= 0) return result;
    result = {
      ...result,
      contentWidth: Math.max(padded.contentWidth, vw),
      contentHeight: Math.max(padded.contentHeight, vh)
    };
    return result;
  }, [
    items,
    cellSize,
    itemGap,
    effectiveItemUnit,
    isFloorMapView,
    mapAreaSize.width,
    mapAreaSize.height,
    viewportSize.width,
    viewportSize.height,
    padSingle
  ]);
  const padForAlign = alignPadSingle ?? 0;
  const initialPositionX = VIEWPORT_TOP_LEFT_MARGIN - padForAlign * zoomConfig.initialScale;
  const initialPositionY = VIEWPORT_TOP_LEFT_MARGIN - padForAlign * zoomConfig.initialScale;
  contentOffsetRef.current = { x: contentOffsetX, y: contentOffsetY };
  const initialAlignRef = (0, import_react.useRef)({
    frame: "",
    done: false
  });
  (0, import_react.useEffect)(() => {
    if (!isFloorMapView || frameResetKey === void 0) return;
    if (initialAlignRef.current.frame !== frameResetKey) {
      initialAlignRef.current = { frame: frameResetKey, done: false };
    }
    if (autoFitOnMount) {
      initialAlignRef.current.done = true;
      return;
    }
    if (alignPadSingle == null) {
      initialAlignRef.current.done = false;
      return;
    }
    if (initialAlignRef.current.done) return;
    let cancelled = false;
    let raf = 0;
    const tick = () => {
      if (cancelled) return;
      const ctx = transformRef.current;
      if (!ctx) {
        raf = requestAnimationFrame(tick);
        return;
      }
      ctx.setTransform(
        initialPositionX,
        initialPositionY,
        zoomConfig.initialScale
      );
      initialAlignRef.current.done = true;
    };
    raf = requestAnimationFrame(tick);
    return () => {
      cancelled = true;
      cancelAnimationFrame(raf);
    };
  }, [
    isFloorMapView,
    frameResetKey,
    alignPadSingle,
    initialPositionX,
    initialPositionY,
    zoomConfig.initialScale,
    transformRef,
    autoFitOnMount
  ]);
  (0, import_react.useEffect)(() => {
    const el = containerRef.current;
    if (!el) return;
    const onFullscreenChange = () => setIsFullscreen(document.fullscreenElement === el);
    document.addEventListener("fullscreenchange", onFullscreenChange);
    return () => document.removeEventListener("fullscreenchange", onFullscreenChange);
  }, []);
  const toggleFullscreen = (0, import_react.useCallback)(() => {
    var _a, _b;
    const el = containerRef.current;
    if (!el) return;
    if (document.fullscreenElement) {
      (_a = document.exitFullscreen) == null ? void 0 : _a.call(document);
    } else {
      (_b = el.requestFullscreen) == null ? void 0 : _b.call(el);
    }
  }, []);
  const fitBounds = (0, import_react.useCallback)(() => {
    const ctx = transformRef.current;
    const container = containerRef.current;
    if (!ctx || !container) return false;
    const wrapper = container.querySelector(".react-transform-wrapper");
    if (!wrapper) return false;
    const wrapperRect = wrapper.getBoundingClientRect();
    if (wrapperRect.width <= 0 || wrapperRect.height <= 0) return false;
    const pixelBox = isFloorMapView && effectiveItemUnit === "pixel" && items.length > 0 ? (0, import_layoutMeasurements.getPixelBoundingBox)(items, cellSize) : null;
    if (pixelBox) {
      const bw = Math.max(1, pixelBox.maxRight - pixelBox.minLeft);
      const bh = Math.max(1, pixelBox.maxBottom - pixelBox.minTop);
      const edgePx = 0;
      const availW = Math.max(1, wrapperRect.width - 2 * edgePx);
      const availH = Math.max(1, wrapperRect.height - 2 * edgePx);
      const raw2 = Math.min(availW / bw, availH / bh);
      const nextScale2 = Math.min(raw2, zoom.max ?? 2);
      const ap = alignPadSingle ?? padSingle;
      const bboxCx = ap + bw / 2;
      const bboxCy = ap + bh / 2;
      const x2 = wrapperRect.width / 2 - bboxCx * nextScale2;
      const y2 = wrapperRect.height / 2 - bboxCy * nextScale2;
      ctx.setTransform(x2, y2, nextScale2);
      return true;
    }
    if (contentWidth <= 0 || contentHeight <= 0) return false;
    const raw = Math.min(
      wrapperRect.width / contentWidth,
      wrapperRect.height / contentHeight
    );
    const nextScale = Math.min(raw, zoom.max ?? 2);
    const padA = alignPadSingle ?? 0;
    const x = VIEWPORT_TOP_LEFT_MARGIN - padA * nextScale;
    const y = VIEWPORT_TOP_LEFT_MARGIN - padA * nextScale;
    ctx.setTransform(x, y, nextScale);
    return true;
  }, [
    contentWidth,
    contentHeight,
    zoom.max,
    transformRef,
    alignPadSingle,
    isFloorMapView,
    effectiveItemUnit,
    items,
    cellSize,
    padSingle
  ]);
  const autoFitOnceRef = (0, import_react.useRef)({
    frame: "",
    done: false
  });
  const prevItemsCountForAutoFitRef = (0, import_react.useRef)(null);
  (0, import_react.useLayoutEffect)(() => {
    if (!isFloorMapView || !autoFitOnMount || frameResetKey === void 0) return;
    const frame = String(frameResetKey);
    if (autoFitOnceRef.current.frame !== frame) {
      autoFitOnceRef.current = { frame, done: false };
      prevItemsCountForAutoFitRef.current = null;
    }
    const itemCount = items.length;
    const prevN = prevItemsCountForAutoFitRef.current;
    if (prevN !== null && prevN === 0 && itemCount > 0) {
      autoFitOnceRef.current.done = false;
    }
    prevItemsCountForAutoFitRef.current = itemCount;
    if (autoFitOnceRef.current.done) return;
    if (effectiveItemUnit === "pixel" && itemCount === 0) {
      return;
    }
    if (contentWidth <= 0 || contentHeight <= 0) return;
    let cancelled = false;
    let raf = 0;
    let attempts = 0;
    const MAX_AUTO_FIT_ATTEMPTS = 160;
    const tick = () => {
      if (cancelled) return;
      if (attempts >= MAX_AUTO_FIT_ATTEMPTS) return;
      const ctx = transformRef.current;
      const container = containerRef.current;
      const wrapper = container == null ? void 0 : container.querySelector(
        ".react-transform-wrapper"
      );
      if (!ctx || !wrapper) {
        attempts += 1;
        raf = requestAnimationFrame(tick);
        return;
      }
      const rect = wrapper.getBoundingClientRect();
      if (rect.width <= 0 || rect.height <= 0) {
        attempts += 1;
        raf = requestAnimationFrame(tick);
        return;
      }
      raf = requestAnimationFrame(() => {
        if (cancelled) return;
        raf = requestAnimationFrame(() => {
          if (cancelled) return;
          const ok = fitBounds();
          if (ok) {
            autoFitOnceRef.current.done = true;
            return;
          }
          attempts += 1;
          if (attempts < MAX_AUTO_FIT_ATTEMPTS) {
            raf = requestAnimationFrame(tick);
          }
        });
      });
    };
    raf = requestAnimationFrame(tick);
    return () => {
      cancelled = true;
      cancelAnimationFrame(raf);
    };
  }, [
    isFloorMapView,
    autoFitOnMount,
    frameResetKey,
    effectiveItemUnit,
    items.length,
    contentWidth,
    contentHeight,
    viewportSize.width,
    viewportSize.height,
    mapAreaSize.width,
    mapAreaSize.height,
    fitBounds,
    transformRef
  ]);
  const lastTransformRef = (0, import_react.useRef)({ x: 0, y: 0, scale: 1 });
  const [isInteractingWithElement, setIsInteractingWithElement] = (0, import_react.useState)(false);
  const prevInteractingRef = (0, import_react.useRef)(false);
  (0, import_react.useEffect)(() => {
    if (isInteractingWithElement) {
      prevInteractingRef.current = true;
      return;
    }
    if (!prevInteractingRef.current) return;
    prevInteractingRef.current = false;
    const saved = lastTransformRef.current;
    const raf = requestAnimationFrame(() => {
      var _a;
      (_a = transformRef.current) == null ? void 0 : _a.setTransform(saved.x, saved.y, saved.scale);
    });
    return () => cancelAnimationFrame(raf);
  }, [isInteractingWithElement, transformRef]);
  return {
    containerRef,
    mapAreaRef,
    viewportSize,
    mapAreaSize,
    contentWidth,
    contentHeight,
    contentOffsetX,
    contentOffsetY,
    initialPositionX,
    initialPositionY,
    zoomConfig,
    scale,
    setScale,
    isFullscreen,
    toggleFullscreen,
    fitBounds,
    lastTransformRef,
    isInteractingWithElement,
    setIsInteractingWithElement
  };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  useFloorMapTransformMetrics
});
