import { __extends } from "tslib";
import { jsx as _jsx } from "react/jsx-runtime";
import { Children, cloneElement, createRef, PureComponent } from 'react';
import { addEventListener } from '../utils/component/event-handler';
import { isForwardRef } from 'react-is';
import { computeOffsetPixels } from './offset';
import isDOMElement from '../utils/isDOMElement';
import { getCurrentPosition } from './position';
import isBrowser from '../utils/isBrowser';
import defer from '../utils/defer';
import { parseBorderWidth, parseFontSize } from './cssom';
var DEFAULT_OFFSET = 0;
var Waypoint = (function (_super) {
    __extends(Waypoint, _super);
    function Waypoint() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.refElement = createRef();
        _this.previousPosition = 4;
        _this.handleScroll = function (event) {
            if (!_this.refElement.current) {
                return;
            }
            var bounds = _this.getBounds();
            var currentPosition = getCurrentPosition(bounds);
            var previousPosition = _this.previousPosition;
            var _a = _this.props, onPositionChange = _a.onPositionChange, onEnter = _a.onEnter, onLeave = _a.onLeave, fireOnRapidScroll = _a.fireOnRapidScroll;
            _this.previousPosition = currentPosition;
            if (previousPosition === currentPosition) {
                return;
            }
            var callbackArg = {
                currentPosition: currentPosition,
                previousPosition: previousPosition,
                event: event,
                waypointTop: bounds.waypointTop,
                waypointBottom: bounds.waypointBottom,
                viewportTop: bounds.viewportTop,
                viewportBottom: bounds.viewportBottom,
            };
            onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(callbackArg);
            if (currentPosition === 1) {
                onEnter === null || onEnter === void 0 ? void 0 : onEnter(callbackArg);
            }
            else if (previousPosition === 1 ||
                previousPosition === 4) {
                onLeave === null || onLeave === void 0 ? void 0 : onLeave(callbackArg);
            }
            var isRapidScrollDown = previousPosition === 2 &&
                currentPosition === 0;
            var isRapidScrollUp = previousPosition === 0 &&
                currentPosition === 2;
            if (fireOnRapidScroll && (isRapidScrollDown || isRapidScrollUp)) {
                onEnter === null || onEnter === void 0 ? void 0 : onEnter({
                    currentPosition: 1,
                    previousPosition: previousPosition,
                    event: event,
                    waypointTop: bounds.waypointTop,
                    waypointBottom: bounds.waypointBottom,
                    viewportTop: bounds.viewportTop,
                    viewportBottom: bounds.viewportBottom,
                });
                onLeave === null || onLeave === void 0 ? void 0 : onLeave({
                    currentPosition: currentPosition,
                    previousPosition: 1,
                    event: event,
                    waypointTop: bounds.waypointTop,
                    waypointBottom: bounds.waypointBottom,
                    viewportTop: bounds.viewportTop,
                    viewportBottom: bounds.viewportBottom,
                });
            }
        };
        return _this;
    }
    Waypoint.prototype.componentDidMount = function () {
        var _this = this;
        if (!isBrowser) {
            return;
        }
        this.cancelOnNextTick = defer(function () {
            _this.cancelOnNextTick = null;
            var children = _this.props.children;
            ensureRefIsUsedByChild(children, _this.refElement.current);
            _this.scrollableAncestor = _this.findScrollableAncestor();
            _this.scrollEventListenerUnsubscribe = addEventListener(_this.scrollableAncestor, 'scroll', _this.handleScroll, { passive: true });
            _this.resizeEventListenerUnsubscribe = addEventListener(window, 'resize', _this.handleScroll, { passive: true });
            _this.handleScroll(null);
        });
    };
    Waypoint.prototype.componentDidUpdate = function () {
        var _this = this;
        if (!isBrowser) {
            return;
        }
        if (!this.scrollableAncestor) {
            return;
        }
        if (this.cancelOnNextTick) {
            return;
        }
        this.cancelOnNextTick = defer(function () {
            _this.cancelOnNextTick = null;
            _this.handleScroll(null);
        });
    };
    Waypoint.prototype.componentWillUnmount = function () {
        var _a, _b, _c;
        if (!isBrowser) {
            return;
        }
        (_a = this.scrollEventListenerUnsubscribe) === null || _a === void 0 ? void 0 : _a.call(this);
        (_b = this.resizeEventListenerUnsubscribe) === null || _b === void 0 ? void 0 : _b.call(this);
        (_c = this.cancelOnNextTick) === null || _c === void 0 ? void 0 : _c.cancel();
    };
    Waypoint.prototype.findScrollableAncestor = function () {
        var _a = this.props, horizontal = _a.horizontal, scrollableAncestor = _a.scrollableAncestor;
        if (scrollableAncestor) {
            return scrollableAncestor;
        }
        var node = this.refElement.current;
        while (node.parentNode) {
            node = node.parentNode;
            if (node === document.body) {
                return window;
            }
            var style = getComputedStyle(node);
            var overflowDirec = horizontal
                ? style.getPropertyValue('overflow-x')
                : style.getPropertyValue('overflow-y');
            var overflow = overflowDirec || style.getPropertyValue('overflow');
            if (overflow === 'auto' || overflow === 'scroll') {
                return node;
            }
        }
        return window;
    };
    Waypoint.prototype.getBounds = function () {
        var horizontal = this.props.horizontal;
        var _a = this.refElement.current.getBoundingClientRect(), left = _a.left, top = _a.top, right = _a.right, bottom = _a.bottom;
        var waypointTop = horizontal ? left : top;
        var waypointBottom = horizontal ? right : bottom;
        var contextHeight;
        var contextScrollTop;
        if (this.scrollableAncestor === window) {
            contextHeight = horizontal ? window.innerWidth : window.innerHeight;
            contextScrollTop = 0;
        }
        else {
            var node = this.scrollableAncestor;
            var boundingBox = node.getBoundingClientRect();
            contextHeight = horizontal ? boundingBox.width : boundingBox.height;
            contextScrollTop = horizontal ? boundingBox.left : boundingBox.top;
        }
        var topOffsetPx = this.getOffset('top', contextHeight);
        var bottomOffsetPx = this.getOffset('bottom', contextHeight);
        var contextBottom = contextScrollTop + contextHeight;
        return {
            waypointTop: waypointTop,
            waypointBottom: waypointBottom,
            viewportTop: contextScrollTop + topOffsetPx,
            viewportBottom: contextBottom - bottomOffsetPx,
        };
    };
    Waypoint.prototype.getOffset = function (pos, contextHeight) {
        var _a, _b;
        var horizontal = this.props.horizontal;
        var prop = pos + "Offset";
        var border = pos === 'top'
            ? "border" + (horizontal ? 'Left' : 'Top') + "Width"
            : "border" + (horizontal ? 'Right' : 'Bottom') + "Width";
        var propOffset = this.props[prop];
        if (propOffset !== 'auto') {
            return computeOffsetPixels(propOffset, contextHeight);
        }
        if (this.scrollableAncestor === window) {
            var styles_1 = getComputedStyle(document.documentElement);
            var getFontSize = function () { return parseFontSize(styles_1.fontSize); };
            return ((_a = parseBorderWidth(styles_1[border], getFontSize, getFontSize)) !== null && _a !== void 0 ? _a : DEFAULT_OFFSET);
        }
        else {
            var styles_2 = getComputedStyle(this.scrollableAncestor);
            var getFontSize = function () { return parseFontSize(styles_2.fontSize); };
            var getRootFontSize = function () {
                return parseFontSize(getComputedStyle(document.documentElement).fontSize);
            };
            return ((_b = parseBorderWidth(styles_2[border], getFontSize, getRootFontSize)) !== null && _b !== void 0 ? _b : DEFAULT_OFFSET);
        }
    };
    Waypoint.prototype.render = function () {
        var _this = this;
        var children = this.props.children;
        if (!children) {
            return (_jsx("span", { ref: this.refElement, style: { fontSize: 0 }, className: "zent-waypoint-marker", "data-zv": 'v10.0.11' }, void 0));
        }
        var child = Children.only(children);
        if (isDOMElement(child) || isForwardRef(child)) {
            var ref = function (node) {
                _this.refElement.current = node;
                var chRef = child.ref;
                if (chRef) {
                    if (typeof chRef === 'function') {
                        chRef(node);
                    }
                    else {
                        chRef.current = node;
                    }
                }
            };
            return cloneElement(child, { ref: ref });
        }
        return cloneElement(child, { innerRef: this.refElement });
    };
    Waypoint.defaultProps = {
        topOffset: DEFAULT_OFFSET,
        bottomOffset: DEFAULT_OFFSET,
        horizontal: false,
        fireOnRapidScroll: true,
    };
    return Waypoint;
}(PureComponent));
export { Waypoint };
function ensureRefIsUsedByChild(children, ref) {
    if (children && !isDOMElement(children) && !ref) {
        throw new Error('<Waypoint> needs a DOM element to compute boundaries. The child you passed is neither a ' +
            'DOM element (e.g. <div>) nor does it use the innerRef prop.\n');
    }
}
