import { useState } from './useState';
import { useRole } from './useRole';
import { useAcl } from './useAcl';
import { useUserConfig } from './useUserConfig';
import axios from 'axios';
import { useRouter } from 'vue-router';
import useNotify from './useNotify';
import { useTokenConfig } from './useTokenConfig';
const TOKEN_MULTIMEDIA = 'tokenMultimedia';
const TOKEN = 'token';

export function useSession() {
    const router = useRouter();
    const { notify } = useNotify();
    let isCheckingToken = false;
    let intervalId = null;

    function getToken() {
        const localToken = localStorage.getItem(TOKEN);
        const sessionToken = sessionStorage.getItem(TOKEN);

        return localToken || sessionToken || '';
    }
    function getTokenMultimedia() {
        const localTokenMultimedia = localStorage.getItem(TOKEN_MULTIMEDIA);
        const sessionTokenMultimedia = sessionStorage.getItem(TOKEN_MULTIMEDIA);

        return localTokenMultimedia || sessionTokenMultimedia || '';
    }

    function setSession(data) {
        let keepLogin = data.keepLogin;
        const storage = keepLogin ? localStorage : sessionStorage;
        storage.setItem(TOKEN, data.token);
        storage.setItem(TOKEN_MULTIMEDIA, data.tokenMultimedia);
        storage.setItem('created', data.created);
        storage.setItem('ttl', data.ttl);
        sessionStorage.setItem('keepLogin', keepLogin);
    }

    function keepLogin() {
        return sessionStorage.getItem('keepLogin');
    }

    function setToken({ token, tokenMultimedia }) {
        const storage = keepLogin() ? localStorage : sessionStorage;
        storage.setItem(TOKEN, token);
        storage.setItem(TOKEN_MULTIMEDIA, tokenMultimedia);
    }
    async function destroyToken(url, storage, key) {
        if (storage.getItem(key)) {
            try {
                await axios.post(url, null, {
                    headers: { Authorization: storage.getItem(key) },
                });
            } catch (error) {
                notify('errors.statusUnauthorized', 'negative');
            } finally {
                storage.removeItem(key);
            }
        }
    }
    async function destroy(destroyTokens = true) {
        const tokens = {
            tokenMultimedia: 'Accounts/logout',
            token: 'VnUsers/logout',
        };
        const storage = keepLogin() ? localStorage : sessionStorage;
        let destroyTokenPromises = [];
        try {
            if (destroyTokens) {
                const { data: isValidToken } = await axios.get('VnUsers/validateToken');
                if (isValidToken)
                    destroyTokenPromises = Object.entries(tokens).map(([key, url]) =>
                        destroyToken(url, storage, key)
                    );
            }
        } finally {
            localStorage.clear();
            sessionStorage.clear();
            await Promise.allSettled(destroyTokenPromises);
            const { setUser } = useState();

            setUser({
                id: 0,
                name: '',
                nickname: '',
                lang: '',
                darkMode: null,
            });

            stopRenewer();
        }
    }

    async function login(data) {
        setSession(data);

        await useRole().fetch();
        await useAcl().fetch();
        await useUserConfig().fetch();
        await useTokenConfig().fetch();

        startInterval();
    }

    async function setLogin(data) {
        const {
            data: { multimediaToken },
        } = await axios.get('VnUsers/ShareToken', {
            headers: { Authorization: data.token },
        });

        if (!multimediaToken) return;

        await login({
            ...data,
            created: Date.now(),
            tokenMultimedia: multimediaToken.id,
        });

        notify('login.loginSuccess', 'positive');

        const currentRoute = router.currentRoute.value;
        if (currentRoute.query?.redirect) {
            router.push(currentRoute.query.redirect);
        } else {
            router.push({ name: 'Dashboard' });
        }
    }

    function isLoggedIn() {
        const localToken = localStorage.getItem(TOKEN);
        const sessionToken = sessionStorage.getItem(TOKEN);
        startInterval();
        return !!(localToken || sessionToken);
    }

    function startInterval() {
        stopRenewer();
        const renewPeriod = +sessionStorage.getItem('renewPeriod');
        if (!renewPeriod) return;
        intervalId = setInterval(() => checkValidity(), renewPeriod * 1000);
    }

    function stopRenewer() {
        clearInterval(intervalId);
    }

    async function renewToken() {
        const _token = getToken();
        const token = await axios.post('VnUsers/renewToken', {
            headers: { Authorization: _token },
        });
        const _tokenMultimedia = getTokenMultimedia();
        const tokenMultimedia = await axios.post('VnUsers/renewToken', {
            headers: { Authorization: _tokenMultimedia },
        });
        setToken({ token: token.data.id, tokenMultimedia: tokenMultimedia.data.id });
    }

    async function checkValidity() {
        const { getTokenConfig } = useState();

        const tokenConfig = getTokenConfig() ?? sessionStorage.getItem('tokenConfig');
        const storage = keepLogin() ? localStorage : sessionStorage;

        const created = +storage.getItem('created');
        const ttl = +storage.getItem('ttl');

        if (isCheckingToken || !created) return;
        isCheckingToken = true;

        const renewPeriodInSeconds = Math.min(ttl, tokenConfig.value.renewPeriod) * 1000;

        const maxDate = created + renewPeriodInSeconds;
        const now = new Date().getTime();

        if (isNaN(renewPeriodInSeconds) || now <= maxDate) {
            return (isCheckingToken = false);
        }

        await renewToken();
        isCheckingToken = false;
    }

    return {
        getToken,
        getTokenMultimedia,
        setToken,
        destroy,
        login,
        setLogin,
        isLoggedIn,
        checkValidity,
        setSession,
        renewToken,
    };
}
