import { takeEvery, select, put, call, all } from 'redux-saga/effects';

import {
    CHANGE_TAB,
    STORE_INITIALIZED,
    CLEAR_TOKENS,
} from 'app/ActionTypes';

import OpenBarbellConfig from 'app/configs/OpenBarbellConfig.json';
import API from 'app/services/API';
import * as AuthSelectors from 'app/redux/selectors/AuthSelectors';
import * as AuthActionCreators from 'app/redux/shared_actions/AuthActionCreators';
import * as DateUtils from 'app/utility/transforms/DateUtils';
import * as Analytics from 'app/services/Analytics';

const TokenSaga = function * TokenSaga() {
    yield all([
        takeEvery(CHANGE_TAB, executeObtainNewTokens),
        takeEvery(STORE_INITIALIZED, executeObtainNewTokens),
        takeEvery(CLEAR_TOKENS, executeObtainNewTokens), // for anonymous
    ]);
};

function* executeObtainNewTokens() {
    const isLoggedIn = yield select(AuthSelectors.getIsLoggedIn);
    if (isLoggedIn) {
        yield call(obtainNewTokens);
    } else {
        yield call(obtainNewAnonymousTokens);
    }
}

function* obtainNewTokens() {
    // check has token
    const refreshToken = yield select(AuthSelectors.getRefreshToken);    
    if (refreshToken === null) {
        console.tron.log("cannot refresh as no refresh token");
        return;
    }

    // check should refresh
    var lastRefreshDate = yield select(AuthSelectors.getLastRefreshDate);
    lastRefreshDate = DateUtils.getDate(lastRefreshDate);
    if (!shouldRequestNewToken(lastRefreshDate)) {
        console.tron.log("hasn't been long enough to refresh " + lastRefreshDate + " " + OpenBarbellConfig.obtainTokenTimer + " vs " + Math.abs(new Date() - lastRefreshDate));
    } else {
        console.tron.log("refreshing tokens");

        try {
            // refresh
            let state = yield select();
            logAttemptRefreshTokenAnalytics(state);
            const json = yield call(API.obtainNewTokens, refreshToken);

            // success
            state = yield select();
            logRefreshedTokenAnalytics(state);
            yield put(AuthActionCreators.saveTokens(json.accessToken, json.refreshToken, new Date()));
        } catch(error) {
            let state = yield select();
            logRefreshTokenErrorAnalytics(state);
            if (error.type !== undefined || typeof error === 'function') {
                yield put(error);
            }
            console.tron.log(JSON.stringify(error));
        }
    }

    // ready
    yield put(AuthActionCreators.tokensReady());
}

function *obtainNewAnonymousTokens() {
    // check has token
    const refreshToken = yield select(AuthSelectors.getRefreshToken);    
    if (refreshToken === null) {
        console.tron.log("cannot refresh as no refresh token");
        return;
    }

    // check should refresh
    var lastRefreshDate = yield select(AuthSelectors.getLastRefreshDate);
    lastRefreshDate = DateUtils.getDate(lastRefreshDate);
    if (!shouldRequestNewToken(lastRefreshDate)) {
        console.tron.log("hasn't been long enough to refresh anonymous " + lastRefreshDate + " " + OpenBarbellConfig.obtainTokenTimer + " vs " + Math.abs(new Date() - lastRefreshDate));
    } else {
        console.tron.log("refreshing anonymous tokens");

        try {
            // refresh
            let state = yield select();
            // TODO: analytics
            // logAttemptRefreshTokenAnalytics(state);
            const json = yield call(API.obtainNewAnonymousTokens, refreshToken);

            // success
            state = yield select();
            // TODO: analytics
            // logRefreshedTokenAnalytics(state);
            yield put(AuthActionCreators.saveTokens(json.accessToken, json.refreshToken, new Date()));
        } catch(error) {
            let state = yield select();
            // TODO: analytics
            // logRefreshTokenErrorAnalytics(state);
            if (error.type !== undefined || typeof error === 'function') {
                yield put(error);
            }
            yield put(AuthActionCreators.logout()); // logging out of a logged out user just clear tokens
            console.tron.log(JSON.stringify(error));
        }
    }

    // ready
    yield put(AuthActionCreators.tokensReady());
}

const shouldRequestNewToken = (lastRefreshDate) => lastRefreshDate === null || Math.abs(new Date() - lastRefreshDate) > OpenBarbellConfig.obtainTokenTimer;

// ANALYTICS

const logAttemptRefreshTokenAnalytics = (state) => {
    Analytics.logEventWithAppState('attempt_refresh_token', {
    }, state);
};

const logRefreshTokenErrorAnalytics = (state) => {
    Analytics.logEventWithAppState('refresh_token_error', {
    }, state);
};

const logRefreshedTokenAnalytics = (state) => {
    Analytics.logEventWithAppState('refreshed_token', {
    }, state);
};

export default TokenSaga;

@@ -2233,32 +2233,53 @@
 rAnalytics(state
+, error, refreshToken
 );%0A            i
@@ -3873,32 +3873,53 @@
 rAnalytics(state
+, error, refreshToken
 );%0A            i
@@ -4610,32 +4610,53 @@
 alytics = (state
+, error, refreshToken
 ) =%3E %7B%0A    Analy
@@ -4656,36 +4656,36 @@
   Analytics.logE
-vent
+rror
 WithAppState('re
@@ -4673,32 +4673,39 @@
 rorWithAppState(
+error, 
 'refresh_token_e
@@ -4709,24 +4709,60 @@
 n_error', %7B%0A
+        refreshToken: refreshToken,%0A
     %7D, state

refresh token error