import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import {Link} from 'react-router';
import {Icon} from './Icon';
import {KeyDownable} from './KeyDownable';
import lang from '../../lang/common/index-en_US';

/*
 * TODO refactor
 * Refactoring strategy:
 * 1) Remove all router usage, if developer want to navigate with this menu - he should make it on his own.
 * 2) Remove window.scroll usage, each page should control page scroll position by itself
 * 3) Remove children usage - it's incorrect and react shows errors about it
 * 4) Rename sub prop to something else (like compact)
 * 5) Move 'isActive' flag outside each item to root prop (like in tabs)
 * 6) a11y - add ariaLabel for each menu config for correct navigation
 */

const CLASS_NAME_MENU = 'rc-menu';

const FORCE_UPDATE_TIMEOUT = 300;

export class Menu extends React.PureComponent<any> {
    static contextTypes = {
        router: PropTypes.object
    };

    static propTypes = {
        config: PropTypes.arrayOf(
            PropTypes.shape({
                id: PropTypes.string,
                name: PropTypes.string,
                link: PropTypes.string,
                children: PropTypes.array,
                onClickHandler: PropTypes.func,
                testAutomationId: PropTypes.string
            })
        ),
        children: PropTypes.node,
        className: PropTypes.string,
        sub: PropTypes.bool,
        testAutomationId: PropTypes.string,
        ariaLabel: PropTypes.string,
        currentLabel: PropTypes.string
    };

    static defaultProps = {
        children: [],
        testAutomationId: null,
        className: null,
        config: null,
        sub: false,
        get ariaLabel() {
            return lang.SIDE_BAR_MENU_ARIA_LABEL;
        },
        get currentLabel() {
            return lang.CURRENT;
        }
    };

    componentDidMount() {
        const {router} = this.context;

        if (router) {
            this.routerListener = router.listen(() => {
                // TODO refactor this weird shit
                setTimeout(() => {
                    this.forceUpdate();
                }, FORCE_UPDATE_TIMEOUT);
            });
        }
    }

    componentWillUnmount() {
        if (this.routerListener) {
            this.routerListener();
        }
    }

    routerListener: any = null;

    isItemSelected = menuItem => {
        const {router} = this.context;

        if (menuItem.link && router && router.isActive(menuItem.link)) {
            return true;
        }

        if (menuItem.isActive) {
            return true;
        }

        if (Array.isArray(menuItem.children)) {
            return menuItem.children.some(this.isItemSelected);
        }

        return false;
    };

    handleLinkClick = () => {
        window.scrollTo(0, 0);
    };

    renderRootMenuItem = (menuItem, index) => this.renderMenuItem(menuItem, index);

    renderNestedMenuItem = (menuItem, index) => this.renderMenuItem(menuItem, index, true);

    renderMenuItem(menuItem, index, nested = false) {
        const {sub} = this.props;
        const {name, link, testAutomationId, id, children, onClickHandler} = menuItem;

        const iconNode = this.renderIcon(menuItem.icon);
        const isCurrentMenuItem = this.isItemSelected(menuItem);
        const classNames = classnames('rc-menu__item', menuItem.className, {
            'rc-menu__item_with-icon': menuItem.icon,
            'rc-menu__item_nested': nested,
            'rc-menu__item_sub': sub,
            'rc-menu__item_active': isCurrentMenuItem,
            // TODO this class was returned for back compatibility with
            active: isCurrentMenuItem
        });

        let content;

        if (!onClickHandler) {
            content = (
                <Link
                    to={link}
                    className={classNames}
                    data-test-automation-id="item"
                    role="menuitem"
                    onClick={this.handleLinkClick}>
                    {iconNode}
                    {name}
                    {isCurrentMenuItem && (
                        <span className="sr-only">, {this.props.currentLabel}</span>
                    )}
                </Link>
            );
        } else {
            content = (
                <KeyDownable
                    onClick={event => {
                        window.scrollTo(0, 0);
                        onClickHandler(event);

                        // TODO refactor this weird shit
                        setTimeout(() => {
                            this.forceUpdate();
                        }, FORCE_UPDATE_TIMEOUT);
                    }}>
                    {keyDownProps => (
                        <button
                            {...keyDownProps}
                            href="javascript:;"
                            className={classNames}
                            data-test-automation-id="item"
                            role="menuitem">
                            {iconNode}
                            {name}
                            {isCurrentMenuItem && (
                                <span className="sr-only">, {this.props.currentLabel}</span>
                            )}
                        </button>
                    )}
                </KeyDownable>
            );
        }

        return (
            <li
                className="rc-menu__item-wrapper"
                key={index}
                id={id}
                data-test-automation-id={testAutomationId}
                role="none">
                {content}
                {this.renderChildren(children, isCurrentMenuItem)}
            </li>
        );
    }

    renderIcon(iconName) {
        if (!iconName) {
            return null;
        }

        const {sub} = this.props;
        const className = classnames('rc-menu__icon', {
            'rc-menu__icon_sub': sub
        });

        return <Icon name={iconName} className={className} aria-hidden="true" />;
    }

    renderChildren(items, isParentActive) {
        if (!items || !isParentActive) {
            return null;
        }

        const className = classnames(CLASS_NAME_MENU, 'rc-menu_nested');

        return <ul className={className}>{items.map(this.renderNestedMenuItem)}</ul>;
    }

    render() {
        const {ariaLabel, sub, children, config} = this.props;
        const className = classnames(CLASS_NAME_MENU, this.props.className, {
            'rc-menu_submenu': sub
        });

        const menuItems = config || children;

        return (
            <nav aria-label={ariaLabel}>
                <ul
                    className={className}
                    role="menubar"
                    aria-label={ariaLabel}
                    data-test-automation-id={this.props.testAutomationId}>
                    {menuItems.map(this.renderRootMenuItem)}
                </ul>
            </nav>
        );
    }
}
