'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import {Icon} from './Icon';
import EventBus from '../utils/EventBus';
import {getElementHeight} from './utils';
import {getConfig, constants} from '../../utils';

const DISABLE_NOTIFICATION = 0;
const OPEN_TIMEOUT = 100; // Wait for render before change className
const ANIMATION_TIMEOUT = 500; // Css animation duration
const DEFAULT_TIMEOUT = 3;

export class Notification extends React.PureComponent<any, any> {
    static propTypes = {
        success: PropTypes.bool,
        warning: PropTypes.bool,
        error: PropTypes.bool,
        danger: PropTypes.bool,
        timeout: PropTypes.number,
        className: PropTypes.string,
        style: PropTypes.object,
        testAutomationId: PropTypes.string,
        children: PropTypes.node,
        onClose: PropTypes.func
    };

    static defaultProps = {
        success: false,
        warning: false,
        error: false,
        danger: false,
        timeout: null,
        className: '',
        style: {},
        testAutomationId: 'notification',
        children: null,
        onClose: null
    };

    static contextTypes = {
        isTopFixedNotification: PropTypes.bool
    };

    constructor(props, context) {
        super(props, context);
        this.state = {
            height: 0,
            open: false,
            //UIA-69650 delay rendering children to support accessibility
            shouldRenderChildren: true
        };
    }

    closeTimeout: any;

    componentDidMount() {
        if (this.waitForTestAutomation()) {
            EventBus.emit(constants.onTestAutomationAwait);
        }
        setTimeout(this.showNotification, OPEN_TIMEOUT);
    }

    componentWillReceiveProps(nextProps) {
        const changed =
            nextProps.success !== this.props.success ||
            nextProps.warning !== this.props.warning ||
            nextProps.error !== this.props.error ||
            nextProps.danger !== this.props.danger ||
            nextProps.timeout !== this.props.timeout ||
            nextProps.className !== this.props.className ||
            nextProps.children !== this.props.children;
        if (changed) {
            this.showNotification();
        }
    }

    componentWillUnmount() {
        this.stopCloseTimeout();
    }

    showNotification = () => {
        if (this.getTimeout() !== DISABLE_NOTIFICATION) {
            let height = getElementHeight(this.refs.notification, true);
            this.setState(
                {
                    height,
                    open: true,
                    shouldRenderChildren: false
                },
                this.startCloseTimeout
            );
        }
    };

    waitForTestAutomation() {
        const timeout = this.getTimeout();
        return this.context.isTopFixedNotification && timeout > 0;
    }

    getTimeout() {
        const {dismissibleAlertDuration = DEFAULT_TIMEOUT} = getConfig();
        return this.props.timeout === null ? dismissibleAlertDuration * 1000 : this.props.timeout;
    }

    startCloseTimeout = () => {
        this.stopCloseTimeout();
        const timeout = this.getTimeout();
        setTimeout(() => {
            this.setState({
                shouldRenderChildren: true
            });
        }, 10);
        if (timeout > 0) {
            this.closeTimeout = setTimeout(this.close, timeout + ANIMATION_TIMEOUT);
        }
    };

    stopCloseTimeout = () => {
        clearTimeout(this.closeTimeout);
    };

    onClose = () => {
        if (this.waitForTestAutomation()) {
            EventBus.emit(constants.onTestAutomationReady);
        }
        if (this.props.onClose) {
            this.props.onClose();
        }
    };

    close = () => {
        this.stopCloseTimeout();
        this.setState({height: 0, open: false}, () => setTimeout(this.onClose, ANIMATION_TIMEOUT));
    };

    render() {
        if (this.getTimeout() === DISABLE_NOTIFICATION) {
            return null;
        }
        let {
            success,
            warning,
            error,
            danger,
            className,
            style,
            testAutomationId,
            children
        } = this.props;

        let wrapperClassName = classnames('notification-wrapper', {
            'notification-open': this.state.open
        });

        let notificationClassName = classnames(className, 'notification', {
            'notification-success': success && !warning && !error && !danger,
            'notification-warning': warning && !error && !danger,
            'notification-error': error && !danger,
            'notification-danger': danger
        });

        return (
            <div className={wrapperClassName} style={{height: this.state.height}}>
                <div
                    className={notificationClassName}
                    onMouseEnter={this.stopCloseTimeout}
                    onMouseMove={this.stopCloseTimeout}
                    onMouseLeave={this.startCloseTimeout}
                    data-test-automation-id={testAutomationId}
                    style={style}
                    role="alert"
                    ref="notification">
                    <span
                        className="notification-close-button"
                        onClick={this.close}
                        aria-hidden="true"
                        data-test-automation-id="closeButton">
                        <Icon name="close" testAutomationId={''} />
                    </span>
                    <span data-test-automation-id="text">
                        {this.state.shouldRenderChildren ? children : null}
                    </span>
                </div>
            </div>
        );
    }
}
