
/**
 * @license Copyright (c) Microsoft Corporation. All rights reserved.
 */

/**
 * MSAL client application configuration
 * https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-client-application-configuration
 */
var msalConfig =
{
	auth:
	{
		clientId: Storage.getItem(STORAGE_ITEM.clientId),
		authority: Helper.getAuthority(Storage.getItem(STORAGE_ITEM.redirectUri)) + (Storage.getItem(STORAGE_ITEM.tenantId) || "common"),
		redirectUri: getRedirectUriToReceiveToken(), // redirecting back here
		navigateToLoginRequestUrl: false
	},
	cache:
	{
		cacheLocation: "localStorage",
		storeAuthStateInCookie: Helper.isIEorEdge()
	},
};

// instantiating MSAL client application
var clientApplication = new msal.PublicClientApplication(msalConfig);

// try to handle redirect flow, if any happened
clientApplication.handleRedirectPromise()
	.then(handleResponse)
	.catch(function (error)
	{
		clientApplication.logger.error(error);
		console.error("MSAL client application handle redirect failed", error);
	});

/**
 * Handles redirect response
 * @param response - redirect response
 */
function handleResponse(response)
{
	// Remove all user accounts in Msal browser cache, if querying action=clearcache is present.
	removeUserAccount();

	// if response contains access token, call back to client
	if (response != null && response.accessToken != null)
	{
		callback(response.accessToken);
	}
	else
	{
		// need to call getAccount here?
		var currentAccounts = clientApplication.getAllAccounts();
		if (!currentAccounts || currentAccounts.length < 1)
		{
			console.log("No active acount found.");
			getToken();
		}
		else if (currentAccounts.length > 1)
		{
			console.log("Several active acount found.");

			var upn = getWindowHashByName("upn");
			if (upn)
			{
				// Get current signed-in account by username
				var currentAccount = clientApplication.getAccountByUsername(upn);

				if (currentAccount)
				{
					console.log("Matching active user account found in MSAL.");
					getToken(currentAccount);
				}
				else
				{
					console.log("User account not found in MSAL.");
					getToken();
				}
			}
			else
			{
				console.log("UPN not present in the login redirect URL.");
				getToken();
			}
		}
		else if (currentAccounts.length === 1)
		{
			console.log("One active account found.");
			getToken(currentAccounts[0]);
		}
	}
}

/**
 * Acquires token silently or triggers redirect flow
 * @param request - request with scope and account information
 */
function getTokenRedirect(request)
{
	if (!request.account)
	{
		console.warn("User auth account is missing. Trigger user interaction flow.");

		return userInteraction(request);
	}

	console.log("Start silent token acquisition");

	return clientApplication.acquireTokenSilent(request)
		.then(function (response)
		{
			if (response.accessToken)
			{
				console.log("Silent token acquisition succeeded");

				callback(response.accessToken);
			}
			else
			{
				throw Error("access_token is empty in response");
			}
		})
		.catch(function (error)
		{
			console.error("Silent token acquisition failed. Send an interactive request", error);
			// fallback to interaction when silent call fails
			return userInteraction(request);
		});
}

/**
 * Acquires token using redirect flow
 * @param request - request with scope and account information
 */
function userInteraction(request)
{
	return clientApplication.loginRedirect(request).catch(function(error)
	{
		console.error("Login redirect failed with error: " + (error && error.errorCode), error);
		callback(null, error.errorCode);
	});
}

/**
 * Calls back to client with either access token vakue or error code
 * @param access_token - access token
 * @param error_code - code of the error happened during authentication/token retrieval
 */
function callback(access_token, error_code)
{
	console.log("Communicating back to caller");

	try
	{
		var parameters = "#";

		if (access_token)
		{
			parameters += "access_token=" + access_token;
		}
		if (error_code)
		{
			parameters += "error_code=" + error_code;
		}

		Helper.navigateToUrl(Storage.getItem(STORAGE_ITEM.redirectUri) + parameters);
	}
	catch (err)
	{
		console.error("Calls back to client failed: ", err);
	}
}

/**
 * Wrapper for token acquisition request
 * @param account - user account to authorize
 */
function getToken(account)
{
	console.log("Constructing login request");

	var request =
	{
		scopes:
			[
				Storage.getItem(STORAGE_ITEM.scope),
			]
	};

	if (account)
	{
		console.log("Add user account to request");
		request["account"] = account;
	}
	else
	{
		console.log("Set prompt = select_account to force user interaction");
		request["prompt"] = "select_account";
	}

	return getTokenRedirect(request);
}

/**
 * Remove all cached user account in MSAL browser cache.
 * */
function removeUserAccount()
{
	var action = getWindowHashByName("action");
	if (action && action.toLowerCase() === "clearcache")
	{
		try
		{
			var isAccountRemoved = clientApplication.browserStorage.removeAllAccounts();
			console.log("Removed all user account in Msal browser cache:" + isAccountRemoved);
		}
		catch (err)
		{
			console.error("Remove user account in MSAL browser cache is failed", err);
		}
	}
}

/**
 * Get query string value from window hash by name.
 */
function getWindowHashByName(key)
{
	var windowHashParams = Helper.hashToObject(window.location.hash)

	if (windowHashParams && windowHashParams[key])
	{
		return windowHashParams[key];
	}

	return;
}

/**
 * Endpoint to receive tokens
 */
function getRedirectUriToReceiveToken()
{
	var redirectUri = document.location.protocol + "//" + document.location.hostname + document.location.pathname;

	console.log("Redirect Url to receive token. " + redirectUri);

	return redirectUri;
}