<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WizdomCorsProxy.aspx.cs" Inherits="GUI.Web.Base.WizdomCorsProxy" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/msal-browser/msal-browser.js"></script>
    <script src="Scripts/msal-browser/msalConfig.js"></script>
    <script src="Scripts/tokenHandlerMsal.js"></script>

    <script type="module">
        const sessionStorageKey = "wzTokenValidTo.<%=Request.QueryString["SPHostUrl"]%>.<%=Request.QueryString["sessionId"] ?? Session.SessionID%>";
        const isOnline = <%=isOnline.ToString().ToLower()%>;
        var IsModulesTabAvailable = false;
        var IsCustomModulesTabAvailable = false;
        var userRoles = [];
        var userLanguage = "";

        let msalConfigAuthData = <%=MsalConfigAuth%>
            msalConfigAuthData.redirectUri = window.location.origin + "/Base/WizdomContextProxy.aspx";
        msalConfig.auth = msalConfigAuthData;
        let myMSALObj = new msal.PublicClientApplication(msalConfig);
        const tokenHandlerMsal = new TokenHandlerMsal( <%=LoginAuthScopes%>, "<%=SPHostUrl%>", "<%=Request.QueryString["sessionId"] ?? Session.SessionID%>",
            "<%=Request.QueryString["userLoginName"].Replace("\\","\\\\")%>", "<%=Request.QueryString["SPLanguage"] %>", "<%=SPClientTag%>", "<%=SPProductNumber%>", myMSALObj);
        await init();

        async function init() {
            const params = new URLSearchParams(window.location.search);
            
            try {
                if (params.get('IsDialog') === 'true') {
                    reportIsReady();
                    window.close();
                }
                else {
                    if (isOnline)
                        await tokenHandlerMsal.msalGenerateToken();

                    userRoles = await getUserRoles();
                    userLanguage = await getUserLanguages();
                    await ensureModernSiteRegistration();
                    reportIsReady();
                }
            } catch (error) {
                console.error(error);
            }
        }

        function reportIsReady() {

            window.parent.postMessage(JSON.stringify({
                command: "WizdomCorsProxySuccess", session: "<%=Request.QueryString["sessionId"] ?? Session.SessionID%>",
                msLeftOnToken: <%=MillisecondsLeftOnToken%>, allWizdomRoles: [<%=AllWizdomRoles%>], rolesForCurrentUser: userRoles,
                upgradeInProgress: <%=UpgradeInProgress.ToString().ToLower() %>, currentUserLanguage: userLanguage
            }), "*");
        }


        function determineUserLoginName() {
            const userLoginNameFromQueryString = "<%=HttpUtility.UrlDecode(Request.QueryString["userLoginName"] ?? "").Replace("\\", "\\\\")%>";

            if (userLoginNameFromQueryString && userLoginNameFromQueryString !== "undefined") {
                return userLoginNameFromQueryString;
            }
            if (<%=isOnline.ToString().ToLower()%>) {
                return window["wizdomLoginName"] || "";
            }
            return "";
        };

        async function getUserRoles() {
            const loginName = determineUserLoginName();

            if (!loginName) {
                console.warn("User login name is not available. Cannot fetch roles.");
                return [];
            }
            try {
                const response = await fetch("WizdomCorsProxy.aspx/GetRolesForUser", {
                    method: "POST",
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ userLoginName: loginName }),
                });
                const data = await response.json();
                return data.d;
            } catch (error) {
                console.error("Erro to fetch roles:", error);
                return [];
            }
        }

        async function ensureModernSiteRegistration() {

            try {
                let isOriginModernPackage = <%=(Request.QueryString["isModern"] == "true").ToString().ToLower()%>;
                if (isOriginModernPackage) {
                    let spHostUrl = "<%=Request.QueryString["spHostUrl"]%>";
                    const response = await fetch("WizdomCorsProxy.aspx/EnsureModernSiteRegistration", {
                        method: "POST",
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ spHostUrl: spHostUrl }),
                    });
                    const data = await response.json();
                    let res = data.d;
                }
            } catch (error) {
                console.error("Erro to Ensure Modern Site Registration:", error);

            } finally {
                return;
            }
        };

        async function getUserLanguages() {
            const loginName = determineUserLoginName();

            if (!loginName) {
                //default is always en-us
                return "en-us";
            }
            try {
                const response = await fetch("WizdomCorsProxy.aspx/GetUserLanguage", {
                    method: "POST",
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ userLoginName: loginName }),
                });
                const data = await response.json();
                return data.d;
            } catch (error) {
                console.error("Erro to fetch Languages:", error);
                return "en-us";
            }
        };

        function requestDownloadSuccess(filename, requestIndex, data, url) {
            var link = document.createElement('a');
            document.body.appendChild(link);
            link.href = window.URL.createObjectURL(data);
            link['download'] = filename;
            link.click();
            window.parent.postMessage(JSON.stringify({
                command: "RequestSuccess",
                requestIndex: requestIndex,
                result: true,
                url: url
            }), "*");
        }

        function requestSuccess(requestIndex, data, url) {
            window.parent.postMessage(JSON.stringify({
                command: "RequestSuccess",
                requestIndex: requestIndex,
                result: data,
                url: url
            }), "*");
        }
        function requestFailed(requestIndex, data, url) {
            window.parent.postMessage(JSON.stringify({
                command: data && data.status === 403 ? "TokenExpired" : "RequestFailed",
                requestIndex: requestIndex,
                result: flatten(data),
                url: url
            }), "*");
        }

        function flatten(obj) {
            var result = {};
            for (var key in obj) {
                result[key] = obj[key];
            }
            return result;
        }

        function makeRequest(message, retry = false) {
            // Determine the environment and set variables accordingly.
            const isOnline = <%=isOnline.ToString().ToLower()%>;
            const sessionId = "<%=Request.QueryString["sessionId"] ?? Session.SessionID%>";
            const spProductNumber = isOnline ? "<%=SPProductNumber%>" : "16";
            let isDownloadRequest = message.isDownloadRequest;

            // Create a promise for the authentication token.
            // If online, use MSAL to get the token. If on-premises, resolve with null.
            const tokenPromise = isOnline ? tokenHandlerMsal.msalGenerateToken() : Promise.resolve(null);

            // Continue the request only after the token promise is resolved.
            tokenPromise.then(function (token) {
                message.url = message.url.replace("&SPHostUrl=undefined", "");
                message.url = message.url.replace("?SPHostUrl=undefined", "?");
                const url = message.url + getQueryString(message.url);
                const xhr = new XMLHttpRequest();

                if (message.isDownloadRequest) {
                    xhr.responseType = 'arraybuffer';
                }
                xhr.open(message.method, url);
                xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
                xhr.setRequestHeader('sessionId', sessionId);
                xhr.setRequestHeader('SPProductNumber', spProductNumber);

                // Add the Authorization header only if a token is present.
                if (token) {
                    xhr.setRequestHeader('Authorization', `Bearer ${token}`);
                }

                xhr.onload = function (e) {
                    if (xhr.status === 200 || xhr.status === 204) {
                        try {
                            if (message.isDownloadRequest) {
                                var filename = "";
                                const blob = new Blob([xhr.response], { type: 'application/octet-stream' });
                                var disposition = xhr.getResponseHeader('Content-Disposition');                                
                                var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                                var matches = filenameRegex.exec(disposition);
                                if (matches != null && matches[1]) {
                                    filename = matches[1].replace(/['"]/g, '');
                                    requestDownloadSuccess(filename, message.requestIndex, blob, message.url);
                                }
                            }
                            else {
                                requestSuccess(message.requestIndex, isDownloadRequest ? e.currentTarget.response : (xhr.responseText ? JSON.parse(xhr.responseText) : xhr.responseText), message.url);
                            }
                        } catch (e) {
                            // Handle JSON parse failures (e.g., stack trace in response).
                            requestSuccess(message.requestIndex, isDownloadRequest ? e.currentTarget.response : xhr.responseText, message.url);
                        }
                    } else {
                        // If a token is invalid and we haven't retried yet...
                        if ((xhr.status === 403 || (xhr.status === 500 && xhr.responseText.startsWith("Error Message:'Invalid Token -"))) && !retry) {
                            sessionStorage.removeItem(sessionStorageKey);

                            // Attempt to refresh the token, but only for online environments.
                            if (isOnline) {
                                tokenHandlerMsal.msalGenerateToken(true).then(() => {
                                    makeRequest(message, true); // Retry the original request. with a new token
                                });
                            } else {
                                requestFailed(message.requestIndex, xhr, message.url);
                            }
                        } else {
                            requestFailed(message.requestIndex, xhr, message.url);
                        }
                    }
                };

                xhr.send(JSON.stringify(message.data));

            }).catch(error => {
                console.error(error);
            }).finally(() => {
                console.log("Request attempt finished.");
            });
        }

        function getUrl(message) {
            var url = message.url + getQueryString(message.url);
            requestSuccess(message.requestIndex, url);
        }
        function getQueryString(url) {
            let userLoginName = "<%=Request.QueryString["userLoginName"].Replace("\\","\\\\")%>";
            if (!userLoginName || userLoginName == undefined || userLoginName == "undefined")
                userLoginName = window["wizdomLoginName"];

            var queryString = "";
            queryString += url.indexOf("?") > 0 ? "&" : "?";
            queryString += "SPCacheKey=<%=Request.Cookies["SPCacheKey"] ==null ? "" : Request.Cookies["SPCacheKey"].Value%>";
            queryString += "&SPLanguage=<%=Request.QueryString["SPLanguage"] %>";
            queryString += "&SPClientTag=<%="0"/*Request.QueryString["SPClientTag"]*/%>";
            queryString += "&userLoginName=" + userLoginName;
            queryString += "&SPLocale=<%=Request.QueryString["SPLocale"]%>";

            if (!queryString.includes("SPHostUrl") && (!url.includes("SPHostUrl")))
                queryString += "&SPHostUrl=<%=SPHostUrl%>";


            return queryString;
        }

        function getAccessToken() {
            if (!isOnline) {
                return null;
            }
            else {
                tokenHandlerMsal.msalGenerateToken(true)
                .then((token) => {
                    window.parent.postMessage(JSON.stringify({
                        command: "wizWizdomAccessToken",
                        accessToken: token
                    }), "*");
                })
                .catch(e => {
                    console.log("Cannot get access token.");
                    return null;
                })
            }
        }
        function postMessageHandler(e) {
            try {
                var message = JSON.parse(e.data);
                if(message.method == "GET_ACCESS_TOKEN"){
                    getAccessToken();
                } else if (message.method == "GETURL")
                    getUrl(message);
                else if (message.method == "PING")
                    reportIsReady();
                else
                    makeRequest(message);
            }
            catch (ex) {

            }
        }

        if (typeof window.addEventListener != 'undefined')
            window.addEventListener('message', postMessageHandler, false);
        else if (typeof window.attachEvent != 'undefined')
            window.attachEvent('onmessage', postMessageHandler);
    </script>
</head>
</html>
