import React, { useEffect, useRef, useState } from "react";
import useNotifications, { moveToToolbarMonitor } from "../../../../../hooks/useNotifications";
import ConditionalWrapper from "../../../../shared/ConditionalWrapper";
import { CSSTransition } from "react-transition-group";
import { NotificationsContext } from "../../../notificationsContext";
import Drawer from "./Drawer";
import { FEAGlobals } from "../../../../../../common";
import { addDockedClasses, dockToToolbarRight, removeDockedClasses, setOpaqueClassName, setUndockedPosition, saveNotificationsCenterWindowState, } from "../NotificationCenterUtils";
import NotificationDetailsView from "../components/NotificationDetailsView";
import { NotificationCenterMainView } from "./NotificationCenterMainView";
import { SelectionMode, ViewMode } from "../../../constants";
import { defaultNotificationCenterControls } from "../NotificationsCenter";
export const NotificationsCenterWindow = (props) => {
    /**
     * References set up to access state inside async callbacks
     */
    const applicationState = useRef(null);
    const uiStateRef = useRef();
    /**
     * State Variables
     */
    const [isInitialized, setIsInitialized] = useState(false);
    const [isCorrectMonitor, setIsCorrectMonitor] = useState(false);
    const [isBoundsSet, setIsBoundsSet] = useState(false);
    const [isWindowShowing, setIsWindowShowing] = useState(false);
    const [reloadMuteFilters, setReloadMuteFilters] = useState(true);
    const [timerId, setTimerId] = useState(null);
    const config = props.getNotificationConfig();
    const [uiState, _setUIState] = props.getUIState();
    const setUIState = (value) => {
        uiStateRef.current = value;
        _setUIState(value);
    };
    const { notifications, addNotification } = useNotifications(props.params);
    /**
     * Setting up context
     */
    const dcp = props.controls ? props.controls : defaultNotificationCenterControls;
    const [drawerControlProps, setDrawerControlProps] = useState(dcp);
    const [viewMode, setViewMode] = useState(ViewMode.CARD);
    const [searchString, setSearchString] = useState("");
    const [filteredNotifications, setFilteredNotifications] = useState([...notifications]);
    const [selectionMode, setSelectionMode] = useState(SelectionMode.NO_SELECTION);
    const [muteFilters, setMuteFilters] = useState([]);
    const [isSelectAll, setSelectAll] = useState(false);
    const [checkedNotifications, setCheckedNotifications] = useState([]);
    const [selectedNotification, setSelectedNotification] = useState(null);
    const notificationsContextValues = {
        viewMode,
        setViewMode,
        selectionMode,
        setSelectionMode,
        drawerControlProps,
        setDrawerControlProps,
        selectedNotification,
        setSelectedNotification,
        searchString,
        setSearchString,
        filteredNotifications,
        checkedNotifications,
        setCheckedNotifications,
        setFilteredNotifications,
        muteFilters,
        setMuteFilters,
        isSelectAll,
        setSelectAll,
    };
    const toggleDockingStatus = () => {
        var _a;
        const isDocked = !((_a = uiStateRef.current) === null || _a === void 0 ? void 0 : _a.isDocked);
        setUIState({
            ...uiState,
            isDocked,
        });
    };
    /**
     * CSS Housekeeping / initialisation
     */
    useEffect(() => {
        document.body.classList.add("notifications-center-body");
        /**
         * If the window is set to transparent, move the content off-screen via CSS
         * so that it slides in from the correct positions.
         *
         * Sliding in and out is handled by CSS animation using the CSSTransition React element
         */
        setOpaqueClassName(config.isTransparent);
        return () => {
            document.body.classList.remove("notifications-center-body");
        };
    }, []);
    /**
     * props.getUIState() gets an async value, wait for a value to be returned
     * from the Notification Service
     */
    useEffect(() => {
        if (!isInitialized && typeof uiState.showCenter !== "undefined") {
            /**
             * Actual values have been returned, the component will now be rendered for the first time
             * and can now be interacted with
             */
            setIsInitialized(true);
        }
        uiStateRef.current = uiState;
    }, [uiState]);
    /**
     * Showing the Center is split into 3 steps:
     * 1. Position it on the correct monitor
     * 2. Resize the window correctly
     * 3. Display the window.
     *
     * This hook positions the window on the correct monitor. It also hides the window and resets the state
     *
     * This hook is activated if the user is toggling the show center button or
     * is toggling the docking button. When toggling the docking, the window will
     * be shown already.
     */
    useEffect(() => {
        if (isInitialized) {
            // The user is toggling the show/hide button
            if (uiState.showCenter) {
                if (timerId) {
                    // We're trying to show the window, remove any delayed timers that are going to hide it.
                    clearTimeout(timerId);
                    setTimerId(null);
                }
                // The user is toggling the docked/undocked button
                if (uiState.isDocked) {
                    addDockedClasses();
                    if (!isCorrectMonitor) {
                        // Move it to the correct monitor while hidden to prevent flicker
                        moveToToolbarMonitor().then(() => {
                            setIsCorrectMonitor(true);
                        });
                    }
                }
                else {
                    /**
                     * No need to move the monitor when undocked, setting the
                     * bounds will set the correct monitor
                     */
                    removeDockedClasses();
                    setIsCorrectMonitor(true);
                }
                /**
                 * Set the docked center to be always on top
                 */
                FEAGlobals.FSBL.Clients.WindowClient.setAlwaysOnTop(uiState.isDocked);
            }
            else {
                /**
                 * We're trying to hide the window.
                 * If the window is transparent the center takes 500ms to slide in and out of the page.
                 * Wait 500ms before hiding the window and resetting the state
                 */
                setTimerId(setTimeout(() => {
                    FEAGlobals.finsembleWindow.hide();
                    setIsWindowShowing(false);
                    setIsCorrectMonitor(false);
                    setIsBoundsSet(false);
                }, config.isTransparent && uiState.isDocked ? 500 : 0));
            }
            saveNotificationsCenterWindowState({
                ...uiStateRef.current,
                isDocked: uiState.isDocked,
            });
        }
    }, [isInitialized, uiState.showCenter, uiState.isDocked, isCorrectMonitor]);
    /**
     * This hook set the window bounds
     *
     * This effect is triggered when showing the window for the first time or the user is
     * toggling the docking state. When toggling the docking, the window will
     * be showing already.
     *
     * The window is on the correct monitor. Let's set the correct position.
     *
     * Note: Not technically the correct monitor when undocked but calling setBounds will
     * correct the monitor from the saved bounds.
     */
    useEffect(() => {
        if (isInitialized && isCorrectMonitor && uiState.showCenter) {
            if (uiState.isDocked) {
                dockToToolbarRight().then(() => {
                    setIsBoundsSet(true);
                });
            }
            else {
                setUndockedPosition(uiState).then(() => {
                    setIsBoundsSet(true);
                });
            }
        }
    }, [isInitialized, isCorrectMonitor, uiState]);
    /**
     * This hook shows the window and brings it to the front.
     *
     * This effect is run when showing the window.
     * The values are initialized, the monitor is correct, the window position is correct.
     * Show the window and bring it to front.
     */
    useEffect(() => {
        if (isInitialized && isCorrectMonitor && isBoundsSet && uiState.showCenter) {
            if (!isWindowShowing) {
                FEAGlobals.finsembleWindow.show().then(() => {
                    setIsWindowShowing(true);
                    FEAGlobals.finsembleWindow.bringToFront();
                });
            }
            else {
                /**
                 * If window is already showing just bring it to front
                 * (avoids bug where window keeps getting kicked down)
                 */
                FEAGlobals.finsembleWindow.bringToFront();
            }
        }
    }, [isInitialized, isCorrectMonitor, isBoundsSet, uiState.showCenter]);
    /**
     * Prevent the window from closing. Hide the window if the user tries to close it.
     */
    useEffect(() => {
        const subscriptionId = FEAGlobals.FSBL.Clients.RouterClient.subscribe("Finsemble.Application.State", (err, response) => {
            applicationState.current = response.data.state;
        });
        const hide = (event) => {
            const publishValue = { ...uiStateRef.current };
            publishValue.showCenter = false;
            setUIState(publishValue);
            if ((applicationState === null || applicationState === void 0 ? void 0 : applicationState.current) !== "closing") {
                try {
                    event.cancel();
                }
                catch (error) {
                    FEAGlobals.FSBL.Clients.Logger.system.error("Error cancelling the window close event", error);
                }
            }
        };
        FEAGlobals.finsembleWindow.addEventListener("close-requested", hide);
        return () => {
            FEAGlobals.FSBL.Clients.RouterClient.unsubscribe(subscriptionId);
            FEAGlobals.finsembleWindow.removeEventListener("close-requested", hide);
        };
    }, []);
    /**
     * If the window bounds have changed, store the new position or force it back to docked position
     * Bounds can change by manual resizing or when Windows Taskbar + Finsemble Toolbar docking changes
     */
    useEffect(() => {
        const boundsChangeListener = (event) => {
            var _a, _b;
            if (((_a = uiStateRef.current) === null || _a === void 0 ? void 0 : _a.showCenter) && ((_b = uiStateRef.current) === null || _b === void 0 ? void 0 : _b.isDocked)) {
                // If the center is docked, force it to resize
                dockToToolbarRight();
            }
            else {
                const value = {
                    ...uiStateRef.current,
                    position: {
                        top: event.data.top,
                        left: event.data.left,
                        height: event.data.height,
                        width: event.data.width,
                    },
                };
                setUIState(value);
                saveNotificationsCenterWindowState(value);
            }
        };
        FEAGlobals.finsembleWindow.addEventListener("bounds-change-end", boundsChangeListener);
        return () => {
            FEAGlobals.finsembleWindow.removeEventListener("bounds-change-end", boundsChangeListener);
        };
    }, []);
    useEffect(() => {
        setFilteredNotifications([...notifications]);
    }, [notifications]);
    // Sets the select all status from user selecting notifications individually
    useEffect(() => {
        if (notifications.length > 0 && checkedNotifications.length === notifications.length) {
            setSelectAll(true);
        }
    }, [checkedNotifications, notifications]);
    useEffect(() => {
        function listenMuteStateChanged(error) {
            if (error) {
                console.error("FinsembleNotificationsMuteStateChannel: ", error);
                FEAGlobals.FSBL.Clients.Logger.system.error("FinsembleNotificationsMuteStateChannel: ", error);
            }
            else {
                setReloadMuteFilters(true);
            }
        }
        FEAGlobals.FSBL.Clients.RouterClient.addListener("FinsembleNotificationsMuteStateChannel", listenMuteStateChanged);
        return () => {
            FEAGlobals.FSBL.Clients.RouterClient.removeListener("FinsembleNotificationsMuteStateChannel", listenMuteStateChanged);
        };
    }, []);
    // Sets the current active mute filters
    useEffect(() => {
        async function loadMuteFilter() {
            return await FEAGlobals.FSBL.Clients.NotificationClient.getMuteFilters();
        }
        loadMuteFilter().then((loadedMuteFilters) => {
            setMuteFilters(loadedMuteFilters);
            setReloadMuteFilters(false);
        });
    }, [reloadMuteFilters]);
    return (React.createElement(ConditionalWrapper, { condition: config.isTransparent && uiState.isDocked, wrapper: (children) => (React.createElement(CSSTransition, { in: uiState.showCenter, timeout: 500, classNames: "drawer", unmountOnExit: true },
            React.createElement(React.Fragment, null, children))) }, isInitialized && (React.createElement(NotificationsContext.Provider, { value: notificationsContextValues },
        React.createElement(Drawer, null, selectedNotification ? (React.createElement(NotificationDetailsView, { notification: selectedNotification })) : (React.createElement(NotificationCenterMainView, { addNotification: addNotification, viewMode: viewMode, notificationCard: props.notificationCard, notificationHeaderRow: props.notificationHeaderRow, notificationListRow: props.notificationListRow, isDocked: uiState.isDocked, toggleDocking: toggleDockingStatus, notifications: notifications, defaultParams: props.params, config: config })))))));
};
//# sourceMappingURL=NotificationsCenterWindow.js.map