/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { Emitter, Event } from '../../../base/common/event.js';
import { DisposableStore } from '../../../base/common/lifecycle.js';
import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js';
import { IUpdateService, State } from './update.js';

export class UpdateChannel implements IServerChannel {

	constructor(private service: IUpdateService) { }

	listen(_: unknown, event: string): Event<any> {
		switch (event) {
			case 'onStateChange': return this.service.onStateChange;
		}

		throw new Error(`Event not found: ${event}`);
	}

	call(_: unknown, command: string, arg?: any): Promise<any> {
		switch (command) {
			case 'checkForUpdates': return this.service.checkForUpdates(arg);
			case 'downloadUpdate': return this.service.downloadUpdate(arg);
			case 'applyUpdate': return this.service.applyUpdate();
			case 'quitAndInstall': return this.service.quitAndInstall();
			case '_getInitialState': return Promise.resolve(this.service.state);
			case 'isLatestVersion': return this.service.isLatestVersion();
			case '_applySpecificUpdate': return this.service._applySpecificUpdate(arg);
			case 'setInternalOrg': return this.service.setInternalOrg(arg);
		}

		throw new Error(`Call not found: ${command}`);
	}
}

export class UpdateChannelClient implements IUpdateService {

	declare readonly _serviceBrand: undefined;
	private readonly disposables = new DisposableStore();

	private readonly _onStateChange = this.disposables.add(new Emitter<State>());
	readonly onStateChange: Event<State> = this._onStateChange.event;

	private _state: State = State.Uninitialized;
	get state(): State { return this._state; }
	set state(state: State) {
		this._state = state;
		this._onStateChange.fire(state);
	}

	constructor(private readonly channel: IChannel) {
		this.disposables.add(this.channel.listen<State>('onStateChange')(state => this.state = state));
		this.channel.call<State>('_getInitialState').then(state => this.state = state);
	}

	checkForUpdates(explicit: boolean): Promise<void> {
		return this.channel.call('checkForUpdates', explicit);
	}

	downloadUpdate(explicit: boolean): Promise<void> {
		return this.channel.call('downloadUpdate', explicit);
	}

	applyUpdate(): Promise<void> {
		return this.channel.call('applyUpdate');
	}

	quitAndInstall(): Promise<void> {
		return this.channel.call('quitAndInstall');
	}

	isLatestVersion(): Promise<boolean | undefined> {
		return this.channel.call('isLatestVersion');
	}

	_applySpecificUpdate(packagePath: string): Promise<void> {
		return this.channel.call('_applySpecificUpdate', packagePath);
	}

	setInternalOrg(internalOrg: string | undefined): Promise<void> {
		return this.channel.call('setInternalOrg', internalOrg);
	}

	dispose(): void {
		this.disposables.dispose();
	}
}
