import React, { useState, useEffect } from 'react';
import { useTransition } from 'react-spring';
import {
    Container,
    Notification,
    Content,
    Life,
    ErrorIcon,
    Message,
    SuccessIcon,
    InfoIcon,
    Spinner,
    MessageContent,
    MessageLife,
    InfoIconNotification,
    SuccessIconNotification,
    ErrorIconNotification,
    Title,
    Desc,
    CloseIcon,
} from './style';

export type IConfigObject = { timeout?: number; config?: { tension?: number; friction?: number; precision?: number } };
export type IMessageFn = (msg: string, messageConfig?: IConfigObject) => void;
export type IItem = { msg: string; key: number };
let id = 0;

const getMsgIcon = (type: 'info' | 'error' | 'success' | 'warning' | 'pending') => {
    switch (type) {
        case 'error':
            return <ErrorIcon />;
        case 'info':
            return <InfoIcon />;
        case 'success':
            return <SuccessIcon />;
        case 'warning':
            return <InfoIcon warning={true} />;
        case 'pending':
            return <Spinner color="#00A5AA" strokeWidth={5} />;
    }
};

const getNotificationIcon = (type: 'info' | 'error' | 'success' | 'warning') => {
    switch (type) {
        case 'error':
            return <ErrorIconNotification />;
        case 'info':
            return <InfoIconNotification />;
        case 'success':
            return <SuccessIconNotification />;
        case 'warning':
            return <InfoIconNotification warning={true} />;
    }
};

function MessageHub({ children, type }: any) {
    const config = { tension: 125, friction: 20, precision: 0.1, clamp: true };
    const [refMap] = useState(() => new WeakMap());
    const [cancelMap] = useState(() => new WeakMap());
    const [items, setItems]: any[] = useState([]);
    const [timeout, setTime] = useState(2000);
    const transitions = useTransition(items, (item: any) => item.key, {
        from: { opacity: 0, height: 0, life: '100%' },
        enter: (item: any) => async (next: any) => await next({ opacity: 1, height: refMap.get(item).offsetHeight }),
        leave: (item: any) => async (next: any, cancel: any) => {
            cancelMap.set(item, cancel);
            await next({ life: '0%' });
            await next({ opacity: 0, height: 0, margin: 0, display: 'none' });
            //await next({ height: 0 });
        },
        onRest: (item: any) => setItems((state: IItem[]) => state.filter((i: IItem) => i.key !== item.key)),
        config: (item: IItem, springState: string) =>
            springState === 'leave' ? [{ duration: timeout }, config, config] : config,
    } as any);

    useEffect(
        () =>
            void children((msg: string, { timeout, ...rest }: any) => {
                const item = { key: id++, msg, ...rest };
                setItems((state: IItem[]) => [...state, item]);
                setTime(s => timeout);
                return () => {
                    cancelMap.get(item) && cancelMap.get(item)();
                    setTimeout(() => {
                        cancelMap.get(item) && cancelMap.get(item)();
                    }, 1001);
                };
            }),
        []
    );
    return (
        <Container type={type}>
            {transitions.map(({ key, item, props: { life, ...style } }: any) =>
                type === 'notification' ? (
                    <Notification key={key} style={style} type={item.type} data-alter={item.alternativeStyle}>
                        <Content
                            ref={(ref: any) => ref && refMap.set(item, ref)}
                            hasIcon={item.type}
                            data-alter={item.alternativeStyle}
                        >
                            {item.title && <Title>{item.title}</Title>}
                            {getNotificationIcon(item.type)}
                            <Desc>{item.msg}</Desc>
                            {item.showProgress && <Life style={{ right: life }} type={item.type} />}
                            <CloseIcon
                                onClick={(e: any) => {
                                    e.stopPropagation();
                                    cancelMap.has(item) && cancelMap.get(item)();
                                }}
                            />
                        </Content>
                    </Notification>
                ) : (
                    <Message key={key} style={style}>
                        <MessageContent ref={(ref: any) => ref && refMap.set(item, ref)}>
                            {getMsgIcon(item.type)}
                            {item.msg}
                            {item.showProgress && <MessageLife type={item.type} style={{ right: life }} />}
                        </MessageContent>
                    </Message>
                )
            )}
        </Container>
    );
}

export default React.forwardRef(function({ type }: any, ref: any) {
    return <MessageHub type={type} children={(add: IMessageFn) => (ref.current = add)} />;
});
