import { channelManager } from './XDM.js';

/**
 * Web SDK version number. Can be specified in an extension's set of demands like: vss-sdk-version/3.0
 */
const sdkVersion = 4.0;
const global = window;
if (global._AzureDevOpsSDKVersion) {
    console.error("The AzureDevOps SDK is already loaded. Only one version of this module can be loaded in a given document.");
}
global._AzureDevOpsSDKVersion = sdkVersion;
/**
 * DevOps host level
 */
var HostType;
(function (HostType) {
    HostType[HostType["Unknown"] = 0] = "Unknown";
    /**
     * The Deployment host
     */
    HostType[HostType["Deployment"] = 1] = "Deployment";
    /**
     * The Enterprise host
     */
    HostType[HostType["Enterprise"] = 2] = "Enterprise";
    /**
     * The organization host
     */
    HostType[HostType["Organization"] = 4] = "Organization";
})(HostType || (HostType = {}));
const hostControlId = "DevOps.HostControl";
const serviceManagerId = "DevOps.ServiceManager";
const parentChannel = channelManager.addChannel(window.parent);
let teamContext;
let webContext;
let hostPageContext;
let extensionContext;
let initialConfiguration;
let initialContributionId;
let userContext;
let hostContext;
let themeElement;
let resolveReady;
const readyPromise = new Promise((resolve) => {
    resolveReady = resolve;
});
/**
 * Register a method so that the host frame can invoke events
 */
function dispatchEvent(eventName, params) {
    const global = window;
    let evt;
    if (typeof global.CustomEvent === "function") {
        evt = new global.CustomEvent(eventName, params);
    }
    else {
        params = params || { bubbles: false, cancelable: false };
        evt = document.createEvent('CustomEvent');
        evt.initCustomEvent(eventName, params.bubbles, params.cancelable, params.detail);
    }
    window.dispatchEvent(evt);
}
parentChannel.getObjectRegistry().register("DevOps.SdkClient", {
    dispatchEvent: dispatchEvent
});
/**
 * Initiates the handshake with the host window.
 *
 * @param options - Initialization options for the extension.
 */
function init(options) {
    return new Promise((resolve) => {
        const initOptions = { ...options, sdkVersion };
        parentChannel.invokeRemoteMethod("initialHandshake", hostControlId, [initOptions]).then((handshakeData) => {
            const context = handshakeData.context;
            hostPageContext = context.pageContext;
            webContext = hostPageContext ? hostPageContext.webContext : undefined;
            teamContext = webContext ? webContext.team : undefined;
            initialConfiguration = handshakeData.initialConfig || {};
            initialContributionId = handshakeData.contributionId;
            extensionContext = context.extension;
            userContext = context.user;
            hostContext = context.host;
            if (handshakeData.themeData) {
                applyTheme(handshakeData.themeData);
                window.addEventListener("themeChanged", (ev) => {
                    applyTheme(ev.detail.data);
                });
            }
            resolveReady();
            resolve();
        });
    });
}
/**
* Register a callback that gets called once the initial setup/handshake has completed.
* If the initial setup is already completed, the callback is invoked at the end of the current call stack.
*/
async function ready() {
    return readyPromise;
}
/**
* Notifies the host that the extension successfully loaded (stop showing the loading indicator)
*/
function notifyLoadSucceeded() {
    return parentChannel.invokeRemoteMethod("notifyLoadSucceeded", hostControlId);
}
/**
* Notifies the host that the extension failed to load
*/
function notifyLoadFailed(e) {
    return parentChannel.invokeRemoteMethod("notifyLoadFailed", hostControlId, [e]);
}
function getWaitForReadyError(method) {
    return `Attempted to call ${method}() before init() was complete. Wait for init to complete or place within a ready() callback.`;
}
/**
* Get the configuration data passed in the initial handshake from the parent frame
*/
function getConfiguration() {
    if (!initialConfiguration) {
        throw new Error(getWaitForReadyError("getConfiguration"));
    }
    return initialConfiguration;
}
/**
* Gets the information about the contribution that first caused this extension to load.
*/
function getContributionId() {
    if (!initialContributionId) {
        throw new Error(getWaitForReadyError("getContributionId"));
    }
    return initialContributionId;
}
/**
* Gets information about the current user
*/
function getUser() {
    if (!userContext) {
        throw new Error(getWaitForReadyError("getUser"));
    }
    return userContext;
}
/**
* Gets information about the host (i.e. an Azure DevOps organization) that the page is targeting
*/
function getHost() {
    if (!hostContext) {
        throw new Error(getWaitForReadyError("getHost"));
    }
    return hostContext;
}
/**
* Get the context about the extension that owns the content that is being hosted
*/
function getExtensionContext() {
    if (!extensionContext) {
        throw new Error(getWaitForReadyError("getExtensionContext"));
    }
    return extensionContext;
}
/**
* Gets information about the team that the page is targeting
*/
function getTeamContext() {
    if (!teamContext) {
        throw new Error(getWaitForReadyError("getTeamContext"));
    }
    return teamContext;
}
/**
* Get the context about the host page
*/
function getPageContext() {
    if (!hostPageContext) {
        throw new Error(getWaitForReadyError("getPageContext"));
    }
    return hostPageContext;
}
/**
* Get the context about the web
*/
function getWebContext() {
    if (!webContext) {
        throw new Error(getWaitForReadyError("getWebContext"));
    }
    return webContext;
}
/**
* Get the contribution with the given contribution id. The returned contribution has a method to get a registered object within that contribution.
*
* @param contributionId - Id of the contribution to get
*/
async function getService(contributionId) {
    return ready().then(() => {
        return parentChannel.invokeRemoteMethod("getService", serviceManagerId, [contributionId]);
    });
}
/**
* Register an object (instance or factory method) that this extension exposes to the host frame.
*
* @param instanceId - unique id of the registered object
* @param instance - Either: (1) an object instance, or (2) a function that takes optional context data and returns an object instance.
*/
function register(instanceId, instance) {
    parentChannel.getObjectRegistry().register(instanceId, instance);
}
/**
* Removes an object that this extension exposed to the host frame.
*
* @param instanceId - unique id of the registered object
*/
function unregister(instanceId) {
    parentChannel.getObjectRegistry().unregister(instanceId);
}
/**
* Fetch an access token which will allow calls to be made to other DevOps services
*/
async function getAccessToken() {
    return parentChannel.invokeRemoteMethod("getAccessToken", hostControlId).then((tokenObj) => { return tokenObj.token; });
}
/**
* Fetch an token which can be used to identify the current user
*/
async function getAppToken() {
    return parentChannel.invokeRemoteMethod("getAppToken", hostControlId).then((tokenObj) => { return tokenObj.token; });
}
/**
* Requests the parent window to resize the container for this extension based on the current extension size.
*
* @param width - Optional width, defaults to scrollWidth
* @param height - Optional height, defaults to scrollHeight
*/
function resize(width, height) {
    const body = document.body;
    if (body) {
        const newWidth = typeof width === "number" ? width : (body ? body.scrollWidth : undefined);
        const newHeight = typeof height === "number" ? height : (body ? body.scrollHeight : undefined);
        parentChannel.invokeRemoteMethod("resize", hostControlId, [newWidth, newHeight]);
    }
}
/**
 * Applies theme variables to the current document
 */
function applyTheme(themeData) {
    if (!themeElement) {
        themeElement = document.createElement("style");
        themeElement.type = "text/css";
        document.head.appendChild(themeElement);
    }
    const cssVariables = [];
    if (themeData) {
        for (const varName in themeData) {
            cssVariables.push("--" + varName + ": " + themeData[varName]);
        }
    }
    themeElement.innerText = ":root { " + cssVariables.join("; ") + " } body { color: var(--text-primary-color) }";
    dispatchEvent("themeApplied", { detail: themeData });
}

export { HostType, applyTheme, getAccessToken, getAppToken, getConfiguration, getContributionId, getExtensionContext, getHost, getPageContext, getService, getTeamContext, getUser, getWebContext, init, notifyLoadFailed, notifyLoadSucceeded, ready, register, resize, sdkVersion, unregister };
//# sourceMappingURL=SDK.js.map
