/**
 * Copyright (c) 2020 Gitpod GmbH. All rights reserved.
 * Licensed under the GNU Affero General Public License (AGPL).
 * See License-AGPL.txt in the project root for license information.
 */

import { IDEFrontendService, IDEFrontendState } from "@gitpod/gitpod-protocol/lib/ide-frontend-service";
import { Disposable, DisposableCollection } from "@gitpod/gitpod-protocol/lib/util/disposable";
import { Emitter } from "@gitpod/gitpod-protocol/lib/util/event";

interface IDEFrontendCapabilities {
    /**
     * Controls whether IDE window can provide the IDE frontend service.
     */
    readonly service?: boolean
}

let state: IDEFrontendState = 'init';
window.addEventListener('beforeunload', e => {
    if (state === 'terminated') {
        // workspace is stopping or stopped avoid to prompt a user with confirmation dialogs
        e.stopImmediatePropagation();
    }
}, { capture: true });

export function create(): IDEFrontendService {
    let failureCause: Error | undefined;
    let capabilities: IDEFrontendCapabilities = { service: false };
    const onDidChangeEmitter = new Emitter<void>();
    let _delegate: IDEFrontendService | undefined;
    const toStop = new DisposableCollection();
    toStop.push(onDidChangeEmitter);
    const doStart = () => {
        if (!_delegate || state !== 'ready') {
            return;
        }
        try {
            toStop.push(_delegate.start());
        } catch (e) {
            console.error('supervisor frontend: IDE frontend start failed:', e)
            failureCause = e;
            state = 'terminated';
            onDidChangeEmitter.fire();
        }
    }
    const service: IDEFrontendService = {
        get state() {
            if (state === 'terminated') {
                return 'terminated';
            }
            if (capabilities.service) {
                return _delegate?.state || 'init';
            }
            return state;
        },
        get failureCause() {
            return _delegate?.failureCause || failureCause;
        },
        onDidChange: onDidChangeEmitter.event,
        start: () => {
            if (state === 'terminated') {
                throw new Error('IDE frontend has been stopped');
            }
            state = 'ready';
            toStop.push(Disposable.create(() => {
                state = 'terminated';
                onDidChangeEmitter.fire();
            }))
            doStart();
            return toStop;
        }
    }
    const capabilitiesElementAttribute = document.getElementById('gitpod-ide-capabilities')?.getAttribute('data-settings');
    capabilities = capabilitiesElementAttribute && JSON.parse(capabilitiesElementAttribute) || capabilities;
    Object.defineProperty(window.gitpod, 'ideService', {
        get() {
            return _delegate;
        },
        set(delegate: IDEFrontendService) {
            if (_delegate) {
                console.error(new Error('ideService is already set'));
                return;
            }
            _delegate = delegate;
            doStart();
            onDidChangeEmitter.fire();
            delegate.onDidChange(() => onDidChangeEmitter.fire());
        }
    });
    return service;
}