
import { __decorate, __param } from '../../../../../../external/tslib/tslib.es6.js';
import { coalesce } from '../../../base/common/arrays.js';
import { CancellationTokenSource } from '../../../base/common/cancellation.js';
import { Disposable, DisposableStore } from '../../../base/common/lifecycle.js';
import { MarshalledId } from '../../../base/common/marshallingIds.js';
import { ILogService } from '../../../platform/log/common/log.service.js';
import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
import { MainContext } from './extHost.protocol.js';
import { ChatAgentResponseStream } from './extHostChatAgents2.js';
import { IExtHostRpcService } from './extHostRpcService.js';
import { ViewColumn, ChatResponsePart, ChatAgentRequest } from './extHostTypeConverters.js';
import { Disposable as Disposable$1, ChatRequestTurn } from './extHostTypes.js';

var ExtHostChatSessions_1;
class ExtHostChatSession {
    constructor(session, extension, request, proxy, commandsConverter, sessionDisposables) {
        this.session = session;
        this.extension = extension;
        this.proxy = proxy;
        this.commandsConverter = commandsConverter;
        this.sessionDisposables = sessionDisposables;
        this._stream = ( new ChatAgentResponseStream(extension, request, proxy, commandsConverter, sessionDisposables));
    }
    get activeResponseStream() {
        return this._stream;
    }
    getActiveRequestStream(request) {
        return ( new ChatAgentResponseStream(
            this.extension,
            request,
            this.proxy,
            this.commandsConverter,
            this.sessionDisposables
        ));
    }
}
let ExtHostChatSessions = class ExtHostChatSessions extends Disposable {
    static { ExtHostChatSessions_1 = this; }
    static { this._sessionHandlePool = 0; }
    constructor(commands, _languageModels, _extHostRpc, _logService) {
        super();
        this.commands = commands;
        this._languageModels = _languageModels;
        this._extHostRpc = _extHostRpc;
        this._logService = _logService;
        this._chatSessionItemProviders = ( new Map());
        this._chatSessionContentProviders = ( new Map());
        this._nextChatSessionItemProviderHandle = 0;
        this._nextChatSessionContentProviderHandle = 0;
        this._sessionMap = ( new Map());
        this._extHostChatSessions = ( new Map());
        this._proxy = ( this._extHostRpc.getProxy(MainContext.MainThreadChatSessions));
        commands.registerArgumentProcessor({
            processArgument: (arg) => {
                if (arg && arg.$mid === MarshalledId.ChatSessionContext) {
                    const id = arg.id;
                    const sessionContent = this._sessionMap.get(id);
                    if (sessionContent) {
                        return sessionContent;
                    }
                    else {
                        this._logService.warn(`No chat session found for ID: ${id}`);
                        return arg;
                    }
                }
                return arg;
            }
        });
    }
    registerChatSessionItemProvider(extension, chatSessionType, provider) {
        const handle = this._nextChatSessionItemProviderHandle++;
        const disposables = ( new DisposableStore());
        this._chatSessionItemProviders.set(handle, { provider, extension, disposable: disposables });
        this._proxy.$registerChatSessionItemProvider(handle, chatSessionType);
        if (provider.onDidChangeChatSessionItems) {
            disposables.add(provider.onDidChangeChatSessionItems(() => {
                this._proxy.$onDidChangeChatSessionItems(chatSessionType);
            }));
        }
        return {
            dispose: () => {
                this._chatSessionItemProviders.delete(handle);
                disposables.dispose();
                this._proxy.$unregisterChatSessionItemProvider(handle);
            }
        };
    }
    registerChatSessionContentProvider(extension, chatSessionType, provider) {
        const handle = this._nextChatSessionContentProviderHandle++;
        const disposables = ( new DisposableStore());
        this._chatSessionContentProviders.set(handle, { provider, extension, disposable: disposables });
        this._proxy.$registerChatSessionContentProvider(handle, chatSessionType);
        return new Disposable$1(() => {
            this._chatSessionContentProviders.delete(handle);
            disposables.dispose();
            this._proxy.$unregisterChatSessionContentProvider(handle);
        });
    }
    async showChatSession(_extension, chatSessionType, sessionId, options) {
        await this._proxy.$showChatSession(chatSessionType, sessionId, ViewColumn.from(options?.viewColumn));
    }
    async $provideChatSessionItems(handle, token) {
        const entry = this._chatSessionItemProviders.get(handle);
        if (!entry) {
            this._logService.error(`No provider registered for handle ${handle}`);
            return [];
        }
        const sessions = await entry.provider.provideChatSessionItems(token);
        if (!sessions) {
            return [];
        }
        const response = [];
        for (const sessionContent of sessions) {
            if (sessionContent.id) {
                this._sessionMap.set(sessionContent.id, sessionContent);
                response.push({
                    id: sessionContent.id,
                    label: sessionContent.label,
                    iconPath: sessionContent.iconPath
                });
            }
        }
        return response;
    }
    async $provideChatSessionContent(handle, id, token) {
        const provider = this._chatSessionContentProviders.get(handle);
        if (!provider) {
            throw ( new Error(`No provider for handle ${handle}`));
        }
        const session = await provider.provider.provideChatSessionContent(id, token);
        const sessionDisposables = ( new DisposableStore());
        const sessionId = ExtHostChatSessions_1._sessionHandlePool++;
        const chatSession = ( new ExtHostChatSession(session, provider.extension, {
            sessionId: `${id}.${sessionId}`,
            requestId: 'ongoing',
            agentId: id,
            message: '',
            variables: { variables: [] },
            location: ChatAgentLocation.Panel,
        }, {
            $handleProgressChunk: (requestId, chunks) => {
                return this._proxy.$handleProgressChunk(handle, id, requestId, chunks);
            },
            $handleAnchorResolve: (requestId, requestHandle, anchor) => {
                this._proxy.$handleAnchorResolve(handle, id, requestId, requestHandle, anchor);
            },
        }, this.commands.converter, sessionDisposables));
        const disposeCts = sessionDisposables.add(( new CancellationTokenSource()));
        this._extHostChatSessions.set(`${handle}_${id}`, { sessionObj: chatSession, disposeCts });
        if (session.activeResponseCallback) {
            Promise.resolve(session.activeResponseCallback(chatSession.activeResponseStream.apiObject, disposeCts.token)).finally(() => {
                this._proxy.$handleProgressComplete(handle, id, 'ongoing');
            });
        }
        return {
            id: sessionId + '',
            hasActiveResponseCallback: !!session.activeResponseCallback,
            hasRequestHandler: !!session.requestHandler,
            history: ( session.history.map(turn => {
                if (turn instanceof ChatRequestTurn) {
                    return { type: 'request', prompt: turn.prompt };
                }
                else {
                    const responseTurn = turn;
                    const parts = coalesce(( responseTurn.response.map(
                        r => ChatResponsePart.from(r, this.commands.converter, sessionDisposables)
                    )));
                    return {
                        type: 'response',
                        parts
                    };
                }
            }))
        };
    }
    async $interruptChatSessionActiveResponse(providerHandle, sessionId, requestId) {
        const key = `${providerHandle}_${sessionId}`;
        const entry = this._extHostChatSessions.get(key);
        entry?.disposeCts.cancel();
    }
    async $disposeChatSessionContent(providerHandle, sessionId) {
        const key = `${providerHandle}_${sessionId}`;
        const entry = this._extHostChatSessions.get(key);
        if (!entry) {
            this._logService.warn(`No chat session found for ID: ${key}`);
            return;
        }
        entry.disposeCts.cancel();
        entry.sessionObj.sessionDisposables.dispose();
        this._extHostChatSessions.delete(key);
    }
    async $invokeChatSessionRequestHandler(handle, id, request, history, token) {
        const entry = this._extHostChatSessions.get(`${handle}_${id}`);
        if (!entry || !entry.sessionObj.session.requestHandler) {
            return {};
        }
        const chatRequest = ChatAgentRequest.to(request, undefined, await this.getModelForRequest(request, entry.sessionObj.extension), [], ( new Map()), entry.sessionObj.extension, this._logService);
        const stream = entry.sessionObj.getActiveRequestStream(request);
        await entry.sessionObj.session.requestHandler(chatRequest, { history: history }, stream.apiObject, token);
        return {};
    }
    async getModelForRequest(request, extension) {
        let model;
        if (request.userSelectedModelId) {
            model = await this._languageModels.getLanguageModelByIdentifier(extension, request.userSelectedModelId);
        }
        if (!model) {
            model = await this._languageModels.getDefaultLanguageModel(extension);
            if (!model) {
                throw ( new Error('Language model unavailable'));
            }
        }
        return model;
    }
};
ExtHostChatSessions = ExtHostChatSessions_1 = ( __decorate([
    ( __param(2, IExtHostRpcService)),
    ( __param(3, ILogService))
], ExtHostChatSessions));

export { ExtHostChatSessions };
