// @ts-ignore
// eslint-disable-next-line
import { openTokenAuthUrl } from '../authentication/actions';

// @ts-ignore
import { getTokenAuthUrl, isTokenAuthEnabled } from '../authentication/functions';
import { getJwtExpirationDate } from '../base/jwt/functions';
import { MEDIA_TYPE } from '../base/media/constants';
import { isLocalTrackMuted } from '../base/tracks/functions.any';
import { getLocationContextRoot, parseURIString } from '../base/util/uri';

import { addTrackStateToURL } from './functions.any';
import logger from './logger';
import { IStore } from './types';


/**
 * Redirects to another page generated by replacing the path in the original URL
 * with the given path.
 *
 * @param {(string)} pathname - The path to navigate to.
 * @returns {Function}
 */
export function redirectWithStoredParams(pathname: string) {
    return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
        const { locationURL } = getState()['features/base/connection'];
        const newLocationURL = new URL(locationURL?.href ?? '');

        newLocationURL.pathname = pathname;
        window.location.assign(newLocationURL.toString());
    };
}

/**
 * Assigns a specific pathname to window.location.pathname taking into account
 * the context root of the Web app.
 *
 * @param {string} pathname - The pathname to assign to
 * window.location.pathname. If the specified pathname is relative, the context
 * root of the Web app will be prepended to the specified pathname before
 * assigning it to window.location.pathname.
 * @param {string} hashParam - Optional hash param to assign to
 * window.location.hash.
 * @returns {Function}
 */
export function redirectToStaticPage(pathname: string, hashParam?: string) {
    return () => {
        const windowLocation = window.location;
        let newPathname = pathname;

        if (!newPathname.startsWith('/')) {
            // A pathname equal to ./ specifies the current directory. It will be
            // fine but pointless to include it because contextRoot is the current
            // directory.
            newPathname.startsWith('./')
                && (newPathname = newPathname.substring(2));
            newPathname = getLocationContextRoot(windowLocation) + newPathname;
        }

        if (hashParam) {
            windowLocation.hash = hashParam;
        }

        windowLocation.pathname = newPathname;
    };
}

/**
 * Reloads the page by restoring the original URL.
 *
 * @returns {Function}
 */
export function reloadWithStoredParams() {
    return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
        const state = getState();
        const { locationURL } = state['features/base/connection'];

        // Preserve the local tracks muted states.
        // @ts-ignore
        const newURL = addTrackStateToURL(locationURL, state);
        const windowLocation = window.location;
        const oldSearchString = windowLocation.search;

        windowLocation.replace(newURL.toString());

        if (newURL.search === oldSearchString) {
            // NOTE: Assuming that only the hash or search part of the URL will
            // be changed!
            // location.replace will not trigger redirect/reload when
            // only the hash params are changed. That's why we need to call
            // reload in addition to replace.
            windowLocation.reload();
        }
    };
}

/**
 * Checks whether tokenAuthUrl is set, we have a jwt token that will expire soon
 * and redirect to the auth url to obtain new token if this is the case.
 *
 * @param {Dispatch} dispatch - The Redux dispatch function.
 * @param {Function} getState - The Redux state.
 * @param {Function} failureCallback - The callback on failure to obtain auth url.
 * @returns {boolean} Whether we will redirect or not.
 */
export function maybeRedirectToTokenAuthUrl(
        dispatch: IStore['dispatch'], getState: IStore['getState'], failureCallback: Function) {
    const state = getState();
    const config = state['features/base/config'];
    const { enabled: audioOnlyEnabled } = state['features/base/audio-only'];
    const { startAudioOnly } = config;
    const { locationURL = { href: '' } as URL } = state['features/base/connection'];
    const audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
    const videoMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO);

    if (!isTokenAuthEnabled(config)) {
        return false;
    }

    // if tokenAuthUrl check jwt if is about to expire go through the url to get new token
    const jwt = state['features/base/jwt'].jwt;
    const expirationDate = getJwtExpirationDate(jwt);

    // if there is jwt and its expiration time is less than 3 minutes away
    // let's obtain new token
    if (expirationDate && expirationDate.getTime() - Date.now() < 3 * 60 * 1000) {
        const room = state['features/base/conference'].room;
        const { tenant } = parseURIString(locationURL.href) || {};

        getTokenAuthUrl(
            config,
            locationURL,
            {
                audioMuted,
                audioOnlyEnabled: audioOnlyEnabled || startAudioOnly,
                skipPrejoin: true,
                videoMuted
            },
            room,
            tenant
        )
            .then((tokenAuthServiceUrl: string | undefined) => {
                if (!tokenAuthServiceUrl) {
                    logger.warn('Cannot handle login, token service URL is not set');

                    return Promise.reject();
                }

                return dispatch(openTokenAuthUrl(tokenAuthServiceUrl));
            })
            .catch(() => {
                failureCallback();
            });

        return true;
    }

    return false;
}

