const getPythonEditorBaseUrl = (version) => {
    const parts = version.split('.');
    if (parts[0] === '0' || parts[0] === '1' || parts[0] === '2') {
        // Legacy version requiring the per version deployment.
        const versionPart = encodeURIComponent(version.replace(/[.]/g, '-'));
        return `https://python-editor-${versionPart}.microbit.org`;
    }
    return `https://python.microbit.org/v/${version}`;
};
export const createPythonEditorURL = (version, lang, controller, queryParams) => {
    const url = new URL(getPythonEditorBaseUrl(version));
    if (lang) {
        url.searchParams.set('l', lang);
    }
    if (controller) {
        url.searchParams.set('controller', controller.toString());
    }
    if (queryParams) {
        for (const [k, v] of Object.entries(queryParams)) {
            url.searchParams.set(k, v);
        }
    }
    return url.toString();
};
export class PythonEditorFrameDriver {
    constructor(options, iframe) {
        Object.defineProperty(this, "options", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: options
        });
        Object.defineProperty(this, "iframe", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: iframe
        });
        Object.defineProperty(this, "ready", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: false
        });
        Object.defineProperty(this, "messageQueue", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        });
        Object.defineProperty(this, "nextId", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 0
        });
        Object.defineProperty(this, "pendingResponses", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: new Map()
        });
        Object.defineProperty(this, "_expectedOrigin", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "expectedOrigin", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: () => {
                if (this._expectedOrigin) {
                    return this._expectedOrigin;
                }
                const src = this.iframe()?.src;
                if (src) {
                    this._expectedOrigin = new URL(src).origin;
                    return this._expectedOrigin;
                }
                return undefined;
            }
        });
        Object.defineProperty(this, "listener", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (event) => {
                const expectedOrigin = this.expectedOrigin();
                if (!expectedOrigin || event.origin !== expectedOrigin) {
                    return;
                }
                const { data } = event;
                if (typeof data !== 'object') {
                    return;
                }
                if (data.type === 'iframeclientready' || data.type === 'pyeditor') {
                    this.ready = true;
                    this.messageQueue.forEach((m) => this.sendMessageNoReadyCheck(m));
                    this.messageQueue.length = 0;
                }
                if (data.type !== 'pyeditor') {
                    return;
                }
                this.handleWorkspaceSync(data);
                switch (data.action) {
                    case 'workspacesave': {
                        return this.options.onWorkspaceSave?.(data);
                    }
                    case 'workspacesync': {
                        return this.options.onWorkspaceSync?.(data);
                    }
                    case 'workspaceloaded': {
                        return this.options.onWorkspaceLoaded?.(data);
                    }
                }
            }
        });
        Object.defineProperty(this, "sendRequest", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (message) => {
                message.response = true;
                if (!message.id) {
                    message.id = (this.nextId++).toString();
                }
                const id = message.id;
                const p = new Promise((resolve, reject) => {
                    this.pendingResponses.set(id, { resolve, reject, message });
                });
                this.sendMessage(message);
                return p;
            }
        });
        Object.defineProperty(this, "sendMessage", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (message) => {
                if (this.ready) {
                    this.sendMessageNoReadyCheck(message);
                }
                else {
                    this.messageQueue.push(message);
                }
            }
        });
        Object.defineProperty(this, "sendMessageNoReadyCheck", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (message) => {
                this.iframe()?.contentWindow?.postMessage(message, '*');
            }
        });
    }
    initialize() {
        window.addEventListener('message', this.listener);
        // If the iframe is already loaded this will ensure we still initialize correctly
        this.iframe()?.contentWindow?.postMessage({
            type: 'iframeclientready',
        }, '*');
    }
    dispose() {
        window.removeEventListener('message', this.listener);
    }
    setOptions(options) {
        this.options = options;
    }
    /**
     * Import a project.
     */
    async importProject(options) {
        await this.sendRequest({
            type: 'pyeditor',
            action: 'importproject',
            ...options,
        });
    }
    async handleWorkspaceSync(event) {
        try {
            if (event.action === 'workspacesync') {
                const projects = await this.options.initialProjects();
                this.sendMessageNoReadyCheck({
                    ...event,
                    success: true,
                    projects,
                });
            }
        }
        catch (e) {
            console.error(e);
        }
    }
}
//# sourceMappingURL=python-editor-frame-driver.js.map