// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

class NavigationStore {
    private screensInStack: string[] = [];
    private modalsInStack: string[] = [];
    private visibleTab = 'Home';
    private tosOpen = false;

    addModalToStack = (modalId: string) => {
        this.removeModalFromStack(modalId);
        this.addScreenToStack(modalId);
        this.modalsInStack.unshift(modalId);
    };

    addScreenToStack = (screenId: string) => {
        this.removeScreenFromStack(screenId);
        this.screensInStack.unshift(screenId);
    };

    clearScreensFromStack = () => {
        this.screensInStack = [];
    };

    getModalsInStack = () => this.modalsInStack;

    getScreensInStack = () => this.screensInStack;

    getVisibleModal = () => this.modalsInStack[0];

    getVisibleScreen = () => this.screensInStack[0];

    getVisibleTab = () => this.visibleTab;

    hasModalsOpened = () => this.modalsInStack.length > 0;

    isToSOpen = () => this.tosOpen;

    popTo = (screenId: string) => {
        const index = this.screensInStack.indexOf(screenId);
        if (index > -1) {
            this.screensInStack.splice(0, index);
        }
    };

    removeScreenFromStack = (screenId: string) => {
        const index = this.screensInStack.indexOf(screenId);
        if (index > -1) {
            this.screensInStack.splice(index, 1);
        }
    };

    removeModalFromStack = (modalId: string) => {
        const indexInStack = this.screensInStack.indexOf(modalId);
        if (indexInStack > -1) {
            // This removes all the screens that were on top of the modal
            this.screensInStack.splice(0, indexInStack + 1);
        }

        const index = this.modalsInStack.indexOf(modalId);
        if (index > -1) {
            this.modalsInStack.splice(index, 1);
        }
    };

    setToSOpen = (open: boolean) => {
        this.tosOpen = open;
    };

    setVisibleTap = (tab: string) => {
        this.visibleTab = tab;
    };

    /**
     * Waits until a screen has been mounted and is part of the stack.
     * Use this function only if you know what you are doing
     * this function will run until the screen appears in the stack
     * and can easily run forever if the screen is never prevesented.
     * @param screenId string
     */
    waitUntilScreenHasLoaded = async (screenId: string) => {
        let found = false;
        while (!found) {
            // eslint-disable-next-line no-await-in-loop
            await (new Promise((r) => requestAnimationFrame(r)));

            found = this.screensInStack.includes(screenId);
        }
    };

    /**
     * Waits until a passed screen is the top screen
     * Use this function only if you know what you are doing
     * this function will run until the screen is in the top
     * @param screenId string
     */
    waitUntilScreenIsTop = async (screenId: string) => {
        let found = false;
        while (!found) {
            // eslint-disable-next-line no-await-in-loop
            await (new Promise((r) => requestAnimationFrame(r)));

            found = this.getVisibleScreen() === screenId;
        }
    };

    /**
     * Waits until a screen has been removed as part of the stack.
     * Use this function only if you know what you are doing
     * this function will run until the screen disappears from the stack
     * and can easily run forever if the screen is never removed.
     * @param screenId string
     */
    waitUntilScreensIsRemoved = async (screenId: string) => {
        let found = false;
        while (!found) {
            // eslint-disable-next-line no-await-in-loop
            await (new Promise((r) => setTimeout(r, 250)));

            found = !this.screensInStack.includes(screenId);
        }
    };
}

export default new NavigationStore();
