import { _objectSpread2 } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
import { _objectWithoutProperties } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectWithoutProperties.js";
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
//#region src/plus/productSelect/components/IntersectionObserver.tsx
const _excluded = [
	"children",
	"className",
	"style"
];
const IntersectionObserverContext = createContext({
	initialized: false,
	register: () => {},
	unregister: () => {}
});
const { Provider, Consumer } = IntersectionObserverContext;
const IntersectionObserverProvider = ({ children, root = null, rootMargin = "0px", threshold = 0, priorityMode }) => {
	const [mounted, setMounted] = useState(false);
	const [initialized, setInitialized] = useState(false);
	const observerRef = useRef(null);
	const callbackMapRef = useRef(/* @__PURE__ */ new Map());
	const findCallback = useCallback((target) => {
		return callbackMapRef.current.get(target);
	}, []);
	const selectPriorityEntry = useCallback((entries, mode) => {
		if (entries.length === 0) return void 0;
		if (entries.length === 1) return entries[0];
		switch (mode) {
			case "top": return entries.reduce((prev, curr) => curr.boundingClientRect.top < prev.boundingClientRect.top ? curr : prev);
			case "bottom": return entries.reduce((prev, curr) => curr.boundingClientRect.bottom > prev.boundingClientRect.bottom ? curr : prev);
			case "left": return entries.reduce((prev, curr) => curr.boundingClientRect.left < prev.boundingClientRect.left ? curr : prev);
			case "right": return entries.reduce((prev, curr) => curr.boundingClientRect.right > prev.boundingClientRect.right ? curr : prev);
			default: return entries[0];
		}
	}, []);
	const observerOptions = useMemo(() => ({
		root,
		rootMargin,
		threshold
	}), [
		root,
		rootMargin,
		threshold
	]);
	const createObserver = useCallback(() => {
		if (typeof window !== "undefined" && !window.IntersectionObserver) {
			console.warn("IntersectionObserver is not supported in this browser");
			return null;
		}
		return new IntersectionObserver((entries) => {
			if (entries.length === 0) return;
			try {
				if (!priorityMode) {
					entries.forEach((entry) => {
						const callback = findCallback(entry.target);
						if (callback) callback(entry);
					});
					return;
				}
				const visibleEntries = [];
				const invisibleEntries = [];
				entries.forEach((entry) => {
					if (entry.isIntersecting) visibleEntries.push(entry);
					else invisibleEntries.push(entry);
				});
				invisibleEntries.forEach((entry) => {
					const callback = findCallback(entry.target);
					if (callback) callback(entry);
				});
				if (visibleEntries.length > 0) {
					const selectedEntry = selectPriorityEntry(visibleEntries, priorityMode);
					if (selectedEntry) {
						const callback = findCallback(selectedEntry.target);
						if (callback) callback(selectedEntry);
					}
				}
			} catch (error) {
				console.error("IntersectionObserver callback error:", error);
			}
		}, observerOptions);
	}, [
		observerOptions,
		priorityMode,
		findCallback,
		selectPriorityEntry
	]);
	const register = useCallback(({ ref, callback }) => {
		if ((ref === null || ref === void 0 ? void 0 : ref.current) && (observerRef === null || observerRef === void 0 ? void 0 : observerRef.current)) {
			const element = ref.current;
			if (callbackMapRef.current.has(element)) return;
			callbackMapRef.current.set(element, callback);
			observerRef.current.observe(element);
		}
	}, []);
	const unregister = useCallback(({ ref }) => {
		if ((ref === null || ref === void 0 ? void 0 : ref.current) && (observerRef === null || observerRef === void 0 ? void 0 : observerRef.current)) {
			const element = ref.current;
			callbackMapRef.current.delete(element);
			observerRef.current.unobserve(element);
		}
	}, []);
	useEffect(() => {
		if (mounted) {
			if (observerRef.current) observerRef.current.disconnect();
			observerRef.current = createObserver();
			setInitialized(true);
		}
	}, [mounted, createObserver]);
	useEffect(() => {
		setMounted(true);
		return () => {
			if (observerRef.current) {
				observerRef.current.disconnect();
				callbackMapRef.current.clear();
				setInitialized(false);
			}
		};
	}, []);
	const contextValue = {
		initialized,
		register,
		unregister
	};
	return /* @__PURE__ */ React.createElement(Provider, { value: contextValue }, children);
};
const useIntersectionTrigger = (elementRef, options = {}) => {
	const { once = false, onHide, onShow } = options;
	const { initialized, register, unregister } = useContext(IntersectionObserverContext);
	const [isIntersecting, setIsIntersecting] = useState(false);
	const cleanup = useCallback(() => unregister({ ref: elementRef }), [elementRef, unregister]);
	const intersectionCallback = useCallback((entry) => {
		if (entry.isIntersecting) {
			onShow === null || onShow === void 0 || onShow(cleanup);
			if (once) unregister({ ref: elementRef });
		} else onHide === null || onHide === void 0 || onHide(cleanup);
		setIsIntersecting(entry.isIntersecting);
	}, [
		onShow,
		onHide,
		once,
		cleanup,
		unregister,
		elementRef
	]);
	const registerRef = useRef();
	registerRef.current = () => {
		return register({
			ref: elementRef,
			callback: intersectionCallback
		});
	};
	useEffect(() => {
		if (initialized) {
			var _registerRef$current;
			(_registerRef$current = registerRef.current) === null || _registerRef$current === void 0 || _registerRef$current.call(registerRef);
		}
		return () => {
			cleanup();
		};
	}, [initialized, cleanup]);
	return { isIntersecting };
};
const IntersectionTrigger = (_ref) => {
	let { children, className, style = {} } = _ref, options = _objectWithoutProperties(_ref, _excluded);
	const elementRef = useRef(null);
	const { isIntersecting } = useIntersectionTrigger(elementRef, options);
	return /* @__PURE__ */ React.createElement("div", {
		className,
		ref: elementRef,
		style: _objectSpread2({
			width: "100%",
			height: "100%"
		}, style)
	}, children);
};
//#endregion
export { IntersectionTrigger, IntersectionObserverProvider as default };
