import React, { Children } from 'react';
import CloseButton from '../CloseButton';
import TextLabel from './components/TextLabel';
import ActionButton from './components/ActionButton';
import { st, classes } from './Notification.st.css.js';
import { StatusComplete, StatusWarning, StatusAlert, } from '@wix/wix-ui-icons-common';
import { dataHooks } from './Notification.constants';
import { timingMap } from '../Transition/constants';
import deprecationLog from '../utils/deprecationLog';
export const LOCAL_NOTIFICATION = 'local';
export const GLOBAL_NOTIFICATION = 'global';
export const STICKY_NOTIFICATION = 'sticky';
export const DEFAULT_AUTO_HIDE_TIMEOUT = 6000;
export const DEFAULT_TIMEOUT = DEFAULT_AUTO_HIDE_TIMEOUT;
const animationsTimeouts = {
    enter: 300,
    exit: 300,
};
const skinIcon = {
    error: React.createElement(StatusAlert, { className: classes.iconStyling }),
    success: React.createElement(StatusComplete, { className: classes.iconStyling }),
    warning: React.createElement(StatusWarning, { className: classes.iconStyling }),
};
function mapChildren(children) {
    const childrenArray = Children.toArray(children);
    return childrenArray.reduce((childrenAsMap, child) => {
        if (!React.isValidElement(child))
            return childrenAsMap;
        const displayName = child.type.displayName;
        switch (displayName) {
            case 'Notification.TextLabel':
                childrenAsMap.label = child;
                break;
            case 'Notification.ActionButton':
                childrenAsMap.ctaButton = child;
                break;
            case 'Notification.CloseButton':
                childrenAsMap.closeButton = React.cloneElement(child, {
                    size: 'small',
                });
                break;
            default:
                break;
        }
        return childrenAsMap;
    }, {});
}
class Notification extends React.PureComponent {
    constructor() {
        super(...arguments);
        this.closeTimeout = null;
        this.transitionTimeout = null;
        this.ref = React.createRef();
        this.childRef = React.createRef();
        this.state = {
            hideByCloseClick: false,
            hideByTimer: false,
            height: 0,
            showChildren: false,
        };
        this._hideNotificationOnCloseClick = () => {
            this.setState({ hideByCloseClick: true });
            setTimeout(() => this.props.onClose && this.props.onClose('hide-by-close-click'), animationsTimeouts.exit + 100);
        };
        this._hideNotificationOnTimeout = () => {
            this.setState({ hideByTimer: true });
            setTimeout(() => this.props.onClose && this.props.onClose('hide-by-timer'), animationsTimeouts.exit + 100);
        };
    }
    UNSAFE_componentWillReceiveProps(nextProps) {
        if (nextProps.show) {
            this._setChildrenVisibility(nextProps);
            this._bypassCloseFlags();
            this._clearCloseTimeout();
            this._startCloseTimer(nextProps);
        }
    }
    componentDidMount() {
        this._setChildrenVisibility(this.props);
        this._startCloseTimer(this.props);
    }
    componentWillUnmount() {
        this._clearCloseTimeout();
        this._clearTransitionTimeout();
    }
    componentDidUpdate(prevProps, prevState) {
        const { showChildren, height, hideByCloseClick, hideByTimer } = this.state;
        if (prevProps.show !== this.props.show ||
            prevState.showChildren !== this.state.showChildren) {
            const show = this._shouldShowNotification(this.props.show);
            if (show) {
                if (showChildren && this.ref.current && height === 0) {
                    this.setState({ height: this._setHeightToChild(this.ref.current) });
                }
            }
            else {
                if (showChildren && height !== 0) {
                    this.setState({ height: 0 });
                }
            }
        }
        if (prevState.hideByCloseClick !== hideByCloseClick ||
            prevState.hideByTimer !== hideByTimer) {
            this._setChildrenVisibility(this.props);
        }
    }
    _setChildrenVisibility({ show }) {
        this._clearTransitionTimeout();
        if (this._shouldShowNotification(show)) {
            this.setState({ showChildren: true });
        }
        else {
            this.setState({ height: 0 });
            this.transitionTimeout = setTimeout(() => {
                this.setState({ showChildren: false });
                this.transitionTimeout = null;
            }, timingMap['medium01']);
        }
    }
    _clearTransitionTimeout() {
        if (this.transitionTimeout) {
            clearTimeout(this.transitionTimeout);
            this.transitionTimeout = null;
        }
    }
    _startCloseTimer({ autoHideTimeout }) {
        if (autoHideTimeout) {
            this.closeTimeout = setTimeout(() => this._hideNotificationOnTimeout(), autoHideTimeout || DEFAULT_AUTO_HIDE_TIMEOUT);
        }
    }
    _clearCloseTimeout() {
        if (this.closeTimeout) {
            clearTimeout(this.closeTimeout);
            this.closeTimeout = null;
        }
    }
    _bypassCloseFlags() {
        this.setState({
            hideByCloseClick: false,
            hideByTimer: false,
        });
    }
    _shouldShowNotification(show) {
        return show && !this.state.hideByCloseClick && !this.state.hideByTimer;
    }
    _setHeightToChild(node) {
        const height = this.childRef && this.childRef.current
            ? this.childRef.current.offsetHeight
            : 0;
        if (node && node.firstChild) {
            node.firstChild.style.height = `${height}px`;
        }
        return height;
    }
    _getChildren() {
        if (!this.state.showChildren) {
            return null;
        }
        const { theme, children } = this.props;
        const skin = this.props.skin || theme;
        const childrenComponents = mapChildren(children);
        const icon = skin ? skinIcon[skin] : undefined;
        return (React.createElement("div", { className: classes.wrapper, style: {
                overflow: 'hidden',
                transition: `height ${timingMap['medium01']}ms`,
                height: this.state.height,
            } },
            React.createElement("div", { "data-hook": dataHooks.notificationContent, className: classes.notification, role: "alert", "aria-labelledby": "notification-label", "aria-live": "polite", ref: this.childRef },
                icon && React.createElement("div", null, icon),
                React.createElement("div", { className: classes.labelWrapper },
                    childrenComponents.label,
                    childrenComponents.ctaButton),
                childrenComponents.closeButton && (React.createElement("div", { "data-hook": dataHooks.notificationCloseButton, className: classes.closeButton, onClick: this._hideNotificationOnCloseClick, children: childrenComponents.closeButton })))));
    }
    render() {
        const { dataHook, theme, type, zIndex } = this.props;
        const skin = this.props.skin || theme;
        if (theme) {
            deprecationLog('<Notification/> - theme prop is deprecated and will be removed in next major version, please use skin instead');
        }
        return (React.createElement("div", { className: st(classes.root, { skin, type }), style: { zIndex }, "data-hook": dataHook, "data-skin": skin, "data-type": type },
            React.createElement("div", { className: classes.animator, style: {
                    overflow: 'hidden',
                    transition: `height ${timingMap['medium01']}ms`,
                    height: this.state.height,
                } },
                React.createElement("div", { ref: this.ref, className: classes.animatorContent }, this._getChildren()))));
    }
}
Notification.displayName = 'Notification';
Notification.defaultProps = {
    theme: 'standard', // TODO: add default value for skin once theme is removed
    type: GLOBAL_NOTIFICATION,
};
const Close = props => (React.createElement(CloseButton, { skin: "lightFilled", ...props }));
Close.displayName = 'Notification.CloseButton';
Notification.CloseButton = Close;
Notification.TextLabel = TextLabel;
Notification.ActionButton = ActionButton;
export default Notification;
//# sourceMappingURL=Notification.js.map