/**
 * Main button
 *
 * @author Ilya Braujer
 * @date 2019-12-26
 */
import * as React from 'react';
import {AlignClassNames, IntentClassNames, Props, SizeClassNames} from './Button.types';
import {createHtmlPropsFilter} from '../../utils/createHtmlPropsFilter';
import {getSizeThemeKey} from '../../utils/getSizeThemeKey';
import {getIntentThemeKey} from '../../utils/getIntentThemeKey';
import {getAlignThemeKey} from '../../utils/getAlignThemeKey';
import {ALIGN, INTENT, PLACEMENT, POPOVER_THEME, SIZE} from '../../constants';
import {joinClassNames} from '../../utils/joinClassNames';
import * as styles from './button.m.scss';
import {renderIcon} from '../../utils/renderIcon';
import {Tooltip} from '../..';

const filterProps = createHtmlPropsFilter<Props, React.ButtonHTMLAttributes<HTMLButtonElement>>([
    'leftIcon',
    'rightIcon',
    'size',
    'intent',
    'children',
    'isActive',
    'isMinimal',
    'isGhost',
    'isDisabled',
    'isFilled',
    'isWaiting',
    'align',
    'isRound',
    'tooltipPlacement',
    'title',
    'tooltipEnterDelay',
    'forwardRef'
]);

const spanStyle = {
    display: 'inline-block',
    cursor: 'not-allowed'
};

export {
    Props as ButtonProps
};

export class Button extends React.Component<Props> {

    onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        const {isDisabled, isWaiting, onClick} = this.props;

        if (isDisabled === true || isWaiting === true || !onClick) {
            return;
        }

        onClick(e);
    }

    renderButton () {
        const props = this.props;

        const {
            size = SIZE.MIDDLE,
            intent = INTENT.DEFAULT,
            align = ALIGN.CENTER
        } = props;

        const sizeThemeKey = getSizeThemeKey<SizeClassNames>('button', size);
        const intentThemeKey = getIntentThemeKey<IntentClassNames>('button', intent);
        const alignThemeKey = getAlignThemeKey<AlignClassNames>('button', align);
        const isWaiting = Boolean(props.isWaiting);
        const isDisabled = Boolean(props.isDisabled) ||  isWaiting;

        const className = joinClassNames(
            styles.button,
            styles[sizeThemeKey],
            styles[intentThemeKey],
            styles[alignThemeKey],
            [styles.buttonIsRound, Boolean(props.isRound)],
            [styles.buttonIsActive, Boolean(props.isActive)],
            [styles.buttonIsMinimal, Boolean(props.isMinimal)],
            [styles.isGhost, Boolean(props.isGhost)],
            [styles.buttonIsDisabled, isDisabled],
            [styles.buttonIsFilled, Boolean(props.isFilled)],
            [styles.buttonHasLeftIcon, Boolean(props.leftIcon)],
            [styles.buttonHasRightIcon, Boolean(props.rightIcon)],
            [styles.buttonHasText, Boolean(props.children)],
        );

        const {onClick, ...buttonHtmlProps} = filterProps(props);

        const buttonProps = {
            ...buttonHtmlProps,
            onClick: this.onClick,
            disabled: isDisabled,
            className
        };

        return (
            <button {...buttonProps} data-component-id={'Button'} ref={this.props.forwardRef}>
                {isWaiting && (renderIcon(
                    'loading',
                    {
                        intent: intent,
                        size
                    },
                    {className: styles.buttonLeftIconContainer}
                ))}
                {Boolean(props.leftIcon) && !isWaiting && (renderIcon(
                    props.leftIcon,
                    {
                        intent: intent,
                        size
                    },
                    {className: styles.buttonLeftIconContainer}
                ))}
                {props.children && (<span className={styles.buttonText}>{props.children}</span>)}
                {Boolean(props.rightIcon) && (renderIcon(
                    props.rightIcon,
                    {
                        intent: intent,
                        size
                    },
                    {className: styles.buttonRightIconContainer}
                ))}
            </button>
        );
    }

    override render () {
        const {title, isDisabled, tooltipPlacement = PLACEMENT.TOP, tooltipEnterDelay = 300} = this.props;

        return (
            <React.Fragment>
                {
                    (title && (
                        <Tooltip
                            overlay={title}
                            placement={tooltipPlacement}
                            mouseEnterDelay={tooltipEnterDelay}
                            theme={POPOVER_THEME.DARK}
                        >
                            {/*
                                Additional span caused by we need to use own ref, but Tooltip overwrites any child ref.
                            */}
                            <span style={isDisabled ? spanStyle : undefined}>
                                {this.renderButton()}
                            </span>
                        </Tooltip>
                    )) || (
                        this.renderButton()
                    )
                }
            </React.Fragment>
        );
    }
}
