import { Unsubscribable } from 'rxjs';
import { ICommandHandlerDescription } from '@vscode/monaco-editor/esm/vs/platform/commands/common/commands';
import { ProviderMap, ClientThreadCommandsShape, WebExtHostCommandShape } from '@workbench-stack/extension-api';

interface CommandEntry {
    command: string;
    callback: (...args: any[]) => any;
}


/** @internal */
export class WebExtHostCommands implements WebExtHostCommandShape, Unsubscribable {

    private registrations = new ProviderMap<CommandEntry>(id => this.proxy.$unregister(id));


    constructor(private proxy: ClientThreadCommandsShape) { }

    /** Porxy method invoked by the client when the client wants to executes a command. */
    public $executeContributedCommand(id: number, args: any[]): Promise<any> {
        const { callback } = this.registrations.get<CommandEntry>(id);
        return Promise.resolve(callback(...args));
    }

    public $getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }> {
        const result: { [id: string]: string | ICommandHandlerDescription } = Object.create(null);
        this._commands.forEach((command, id) => {
            let { description } = command;
            if (description) {
                result[id] = description;
            }
        });
        return Promise.resolve(result);
    }

    /**
     * Extension API method invoked directly when an extension wants to execute a command. It calls to the client
     * to execute the command because the desired command might be implemented on the client (or otherwise not in this
     * extension host).
     */
    public executeCommand(command: string, args: any[]): Promise<any> {
        return this.proxy.$executeCommand<any>(command, args);
    }

    public registerCommand(entry: CommandEntry): Unsubscribable {
        const { id, subscription } = this.registrations.add(entry);
        console.log('register command', { id, entry })
        this.proxy.$registerCommand(id, entry.command);
        return subscription;
    }

    public unsubscribe(): void {
        this.registrations.unsubscribe();
    }
}
