import React, { FC, memo, useEffect, useMemo, useState }         from 'react';
import { cn }                                                    from '../../util/bem';
import { externalClasses, MediaPropsType }                       from '../../util/externalClasses';
import { FormSizesType, IconColorType, SizeType, TextColorType } from '../../util/global-props';
import { Icon }                                                  from '../icon/icon.component';
import { iconMap }                                               from '../icon/icon.library';
import { Loader, loaderSize }                                    from '../loader/loader.component';
import './button.component.scss';

export type ButtonPropsType = {
    className?: string;
    children?: React.ReactNode;
    before?: React.ReactNode;
    after?: React.ReactNode;
    type?: 'button' | 'submit' | 'reset';
    icon?: keyof typeof iconMap;
    iconAfter?: boolean;
    iconFloat?: 'left' | 'right';
    iconColor?: IconColorType;
    iconMargin?: SizeType;
    iconSize?: number;

    fullWidthContent?: boolean;
    align?: 'left' | 'center' | 'right';
    viewType?: 'primary'
      | 'primary-green'
      | 'primary-white'
      | 'white'
      | 'white-border-grey-3'
      | 'secondary'
      | 'dark'
      | 'transparent-black'
      | 'transparent-grey'
      | 'transparent-transparent'
      | 'transparent-transparent-border-grey-3'
      | 'transparent-white' | 'alert' | 'violet';
    size?: FormSizesType;
    color?: TextColorType;
    bold?: boolean;
    uppercase?: boolean;
    active?: boolean;

    loading?: boolean;
    fullWidth?: boolean;
    rounded?: boolean;
    disabled?: boolean;
    flex?: number | string;
    margin?: SizeType;
    style?: React.CSSProperties;
    hide?: MediaPropsType;
    disableBorderRadius?: boolean;
    squareBorderRadius?: boolean;

    data?: Record<string, string>;
    ref?: React.Ref<HTMLButtonElement>;
    onClick?: React.EventHandler<React.MouseEvent<HTMLButtonElement, PointerEvent>>;
    onFocus?: React.EventHandler<React.FocusEvent<HTMLButtonElement>>;
    onMouseLeave?: React.EventHandler<React.MouseEvent<HTMLButtonElement, PointerEvent>>;
    onMouseEnter?: React.EventHandler<React.MouseEvent<HTMLButtonElement, PointerEvent>>;
}

const className = cn('button');

export const Button: FC<ButtonPropsType> = memo((props) => {
    const [ loading, setLoading ] = useState(false);
    const getIconColor = () => {
        if (props.iconColor) {
            return props.iconColor;
        }
        if (props.viewType === 'primary' || props.viewType === 'alert' || props.viewType === 'dark') {
            return 'white';
        }
        return 'dark';
    };
    const iconFloatStyle = useMemo(() => props.iconFloat && { [ `margin-${ (() => (props.iconFloat === 'left' ? 'right' : 'left'))() }` ]: 'auto' }, [ props.iconFloat ]);
    const getContent = () => (
        <span className={ className('content', { fullWidth: props.fullWidthContent }) }>
            { props.before }
            { props.icon && !props.iconAfter && (
                <Icon
                    style={ iconFloatStyle }
                    margin={ props.iconMargin }
                    name={ props.icon }
                    size={ props.iconSize || undefined }
                    color={ getIconColor() }
                />
            ) }
            { props.children }
            { props.icon && props.iconAfter && (
                <Icon
                    style={ iconFloatStyle }
                    margin={ props.iconMargin }
                    name={ props.icon }
                    size={ props.iconSize || undefined }
                    color={ getIconColor() }
                />
            ) }
            { props.after }
        </span>
    );
    const getLoader = () => (
        <div className={ className('loader') }>
            <Loader
                color={ (props.viewType === 'primary' || props.viewType === 'alert') ? 'white' : 'blue' }
                size={ loaderSize[ props.size as keyof typeof loaderSize ] }
            />
        </div>
    );
    useEffect(() => {
        if (props.loading) {
            setTimeout(() => setLoading(true), 100);
        }
        if (!props.loading) {
            setTimeout(() => setLoading(false), 100);
        }
    }, [ props.loading ]);

    return (
        // eslint-disable-next-line react/button-has-type
        <button
            { ...props.data }
            type={ props.type }
            className={ className({
                size:                props.size,
                align:               props.align,
                type:                props.viewType,
                fullWidth:           props.fullWidth,
                rounded:             props.rounded,
                disabled:            props.disabled,
                margin:              props.margin,
                flex:                props.flex,
                noContent:           !props.children,
                color:               props.color,
                bold:                props.bold,
                uppercase:           props.uppercase,
                disableBorderRadius: props.disableBorderRadius,
                squareBorderRadius:  props.squareBorderRadius,
                active:              props.active,
                loading
            }, null, props.className, externalClasses({ media: props.hide })) }
            onClick={ props.onClick }
            onFocus={ props.onFocus }
            onMouseLeave={ props.onMouseLeave }
            onMouseEnter={ props.onMouseEnter }
            style={ props.style }
            ref={ props.ref }
        >
            { getContent() }
            { props.loading && getLoader() }

        </button>
    );
});

Button.defaultProps = {
    type:       'button',
    size:       'md',
    viewType:   'primary',
    iconMargin: 'xs',
    iconAfter:  false,
    bold:       true
};
