/*
 * Copyright (c) 2020 Adrian Dobre - GPL v3 License.
 *
 * This file is subject to the terms and conditions defined in
 * the 'LICENSE.txt' file, which is part of this source code package.
 */

import React from 'react';

import Grow from '@material-ui/core/Grow';
import Alert from '@material-ui/lab/Alert';
import { v4 } from 'uuid';
import SimplePubSub, { PubSubEvent } from '../../utils/SimplePubSub';
import styles from './UiConsoleComponentStyle.module.scss';

export enum UIConsoleAlertType {
    ERROR = 'error',
    WARNING = 'warning',
    INFO = 'info',
    SUCCESS = 'success'
}

interface UIConsoleAlert {
    id: string;
    type: UIConsoleAlertType;
    message: string;
    dismissed?: boolean;
}

export interface UiConsoleComponentState {
    alerts: UIConsoleAlert[];
}

export default class UiConsoleComponent extends React.PureComponent<{}, UiConsoleComponentState> {
    private static eventsToTypeMap: { [k in PubSubEvent]?: UIConsoleAlert['type'] } = {
        [PubSubEvent.UI_CONSOLE_ERROR]: UIConsoleAlertType.ERROR,
        [PubSubEvent.UI_CONSOLE_WARN]: UIConsoleAlertType.WARNING,
        [PubSubEvent.UI_CONSOLE_INFO]: UIConsoleAlertType.INFO,
        [PubSubEvent.UI_CONSOLE_SUCCESS]: UIConsoleAlertType.SUCCESS
    };

    static showMessage(type: UIConsoleAlertType, message: string): void {
        const pubSubEventKey = Object
            .keys(UiConsoleComponent.eventsToTypeMap)
            .find((key: string) => {
                const psek = key as unknown as keyof PubSubEvent;
                // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                // @ts-ignore
                return UiConsoleComponent.eventsToTypeMap[psek] === type;
            });
        if (pubSubEventKey) {
            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
            // @ts-ignore
            SimplePubSub.publish(pubSubEventKey as unknown as keyof PubSubEvent, { message: message });
        }
    }

    constructor(props: {}) {
        super(props);
        this.state = {
            alerts: []
        };

        Object
            .keys(UiConsoleComponent.eventsToTypeMap)
            .forEach((key: string) => {
                const pubSubEventKey = key as unknown as PubSubEvent;
                SimplePubSub.subscribe(pubSubEventKey, (ev) => {
                    const alertType = UiConsoleComponent.eventsToTypeMap[pubSubEventKey] as UIConsoleAlertType;
                    const newAlert = {
                        id: v4(),
                        message: ev.message,
                        type: alertType
                    };

                    if ([UIConsoleAlertType.INFO, UIConsoleAlertType.SUCCESS].includes(alertType)) {
                        setTimeout(() => {
                            this.onAlertDismissed(newAlert);
                        }, 5000);
                    }

                    this.setState((prevState) => {
                        const alerts = [...prevState.alerts];
                        alerts.unshift(newAlert);
                        return {
                            alerts: alerts.slice(0, 5)
                        };
                    });
                });
            });
    }

    onAlertDismissed(alert: UIConsoleAlert): void {
        this.setState((prevState) => ({
            alerts: prevState.alerts.map((prevAlert) => {
                if (prevAlert === alert) {
                    // eslint-disable-next-line no-param-reassign
                    prevAlert.dismissed = true;
                }
                return prevAlert;
            })
        }));
        setTimeout(() => {
            // eslint-disable-next-line no-shadow
            this.setState((prevState) => ({
                // eslint-disable-next-line no-shadow
                alerts: prevState.alerts.filter((prevAlert) => !prevAlert.dismissed)
            }));
        }, 200);
    }

    render(): JSX.Element {
        return (
            <div className={styles.uiConsole}>
                {this.state.alerts
                    .map((alert) => (
                        <Grow
                            key={alert.id}
                            in={!alert.dismissed}
                        >
                            <Alert
                                className={styles.consoleAlert}
                                severity={alert.type}
                                variant="filled"
                                onClose={(): void => this.onAlertDismissed(alert)}
                            >
                                {alert.message}
                            </Alert>
                        </Grow>
                    ))}
            </div>
        );
    }
}