import React, {MouseEvent, forwardRef, ReactNode, useState, useMemo, CSSProperties, MouseEventHandler} from 'react';
import {Colors, Palette, PaletteType} from '@core0/theme';
import {Icon, IconType} from '@core0/icon';
import {Spinner} from '@core0/spinner';
import {Tooltip} from '@core0/tooltip';
import {useFormContext} from '@core0/contexts';
import cls from 'classnames';
import cn from './abstractButton.module.styl';

export interface AbstractButtonProps {
    color?: PaletteType;
    spinnerColor?: string;
    inverse?: boolean;
    icon?: IconType;
    iconSize?: 'small' | 'regular';
    iconPlacement?: 'left' | 'right';
    label?: string;
    children?: ReactNode | Element[];
    showLoadingOnClick?: boolean;
    loading?: boolean;
    tooltip?: string | ReactNode;
    submit?: boolean;
    type?: 'submit' | 'reset' | 'button';
    disabled?: boolean;
    className?: string;
    style?: CSSProperties;
    onClick?: MouseEventHandler;
}

export const AbstractButton = forwardRef<HTMLButtonElement, AbstractButtonProps>((props, hostElmRef) => {
    const {
        onClick = () => {},
        type = 'button',
        className = '',
        disabled = false,
        label,
        icon,
        iconSize,
        iconPlacement = 'left',
        style = {},
        children,
        showLoadingOnClick = false,
        loading = false,
        tooltip,
        color,
        spinnerColor,
        inverse = false,
        submit = false
    } = props;
    const ctx = useFormContext();
    const [localLoading, setLocalLoading] = useState<boolean>(false);
    const isLoading = loading || localLoading;
    const spinnerStyle = useMemo(() => {
        if (inverse) {
            return {'--spinner-bg': Colors.white} as CSSProperties;
        }
        if (color) {
            return {'--spinner-bg': Palette[color].main} as CSSProperties;
        }
        return {};
    }, [inverse, color])

    async function buttonClickHandler(evt: MouseEvent<HTMLButtonElement>) {
        evt.stopPropagation();

        if (!disabled) {
            if (showLoadingOnClick) setLocalLoading(true);

            if (submit && ctx != null) ctx.submit();

            await onClick(evt);

            if (showLoadingOnClick) setLocalLoading(false);
        }
    }

    return (
        <button
            ref={hostElmRef}
            className={cls(className, cn.abstractButton)}
            type={type}
            style={style}
            disabled={disabled || isLoading}
            onClick={buttonClickHandler}
        >
            {icon &&
                !label &&
                !children &&
                (isLoading ?
                    <Spinner size="small" color={spinnerColor} style={spinnerStyle} />
                    :
                    <Icon type={icon} className={cls(cn.icon, {[cn.small]: iconSize === 'small'})} />)}

            {(label || children) && (
                <>
                    {icon &&
                        iconPlacement === 'left' &&
                        (isLoading ? (
                            <Spinner size="small" color={spinnerColor} className={cls(cn.paddedLeftIcon)} style={spinnerStyle} />
                        ) : (
                            <Icon
                                type={icon}
                                className={cls(cn.icon, cn.paddedLeftIcon, {[cn.small]: iconSize === 'small'})}
                            />
                        ))}
                    {label}
                    {children}
                    {icon &&
                        iconPlacement === 'right' &&
                        (isLoading ? (
                            <Spinner size="small" color={spinnerColor} className={cls(cn.paddedRightIcon)} style={spinnerStyle} />
                        ) : (
                            <Icon
                                type={icon}
                                className={cls(cn.icon, cn.paddedRightIcon, {[cn.small]: iconSize === 'small'})}
                            />
                        ))}
                </>
            )}

            {tooltip && !isLoading && (
                <Tooltip style={{wordBreak: 'break-all'}}>
                    {tooltip}
                </Tooltip>
            )}
        </button>
    );
});
