
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { CancellationToken } from '../../../../base/common/cancellation.js';
import { Emitter } from '../../../../base/common/event.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import '../../../../base/common/observableInternal/index.js';
import { URI, isUriComponents } from '../../../../base/common/uri.js';
import { localize } from '../../../../nls.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
import { ILogService } from '../../../../platform/log/common/log.service.js';
import { StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IStorageService } from '../../../../platform/storage/common/storage.service.js';
import { IChatAgentService } from './participants/chatAgents.service.js';
import { ChatContextKeys } from './actions/chatContextKeys.js';
import { ChatConfiguration, ChatModeKind } from './constants.js';
import { PromptsStorage, isCustomAgentVisibility, ExtensionAgentSourceType } from './promptSyntax/service/promptsService.js';
import { IPromptsService } from './promptSyntax/service/promptsService.service.js';
import { Target } from './promptSyntax/promptTypes.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { hash } from '../../../../base/common/hash.js';
import { isString } from '../../../../base/common/types.js';
import { isTarget } from './promptSyntax/languageProviders/promptFileAttributes.js';
import { constObservable } from '../../../../base/common/observableInternal/observables/constObservable.js';
import { observableValue } from '../../../../base/common/observableInternal/observables/observableValue.js';
import { transaction } from '../../../../base/common/observableInternal/transaction.js';

var ChatModeService_1;
let ChatModeService = class ChatModeService extends Disposable {
    static {
        ChatModeService_1 = this;
    }
    static {
        this.CUSTOM_MODES_STORAGE_KEY = "chat.customModes";
    }
    constructor(
        promptsService,
        chatAgentService,
        contextKeyService,
        logService,
        storageService,
        configurationService
    ) {
        super();
        this.promptsService = promptsService;
        this.chatAgentService = chatAgentService;
        this.logService = logService;
        this.storageService = storageService;
        this.configurationService = configurationService;
        this._customModeInstances = ( new Map());
        this._onDidChangeChatModes = this._register(( new Emitter()));
        this.onDidChangeChatModes = this._onDidChangeChatModes.event;
        this.hasCustomModes = ChatContextKeys.Modes.hasCustomChatModes.bindTo(contextKeyService);
        this.agentModeDisabledByPolicy = ChatContextKeys.Modes.agentModeDisabledByPolicy.bindTo(contextKeyService);
        this.updateAgentModePolicyContextKey();
        this.loadCachedModes();
        void this.refreshCustomPromptModes(true);
        this._register(this.promptsService.onDidChangeCustomAgents(() => {
            void this.refreshCustomPromptModes(true);
        }));
        this._register(this.storageService.onWillSaveState(() => this.saveCachedModes()));
        this._register(this.configurationService.onDidChangeConfiguration(e => {
            if (e.affectsConfiguration(ChatConfiguration.AgentEnabled)) {
                this.updateAgentModePolicyContextKey();
                this._onDidChangeChatModes.fire();
            }
        }));
        let didHaveToolsAgent = this.chatAgentService.hasToolsAgent;
        this._register(this.chatAgentService.onDidChangeAgents(() => {
            if (didHaveToolsAgent !== this.chatAgentService.hasToolsAgent) {
                didHaveToolsAgent = this.chatAgentService.hasToolsAgent;
                this._onDidChangeChatModes.fire();
            }
        }));
    }
    loadCachedModes() {
        try {
            const cachedCustomModes = this.storageService.getObject(ChatModeService_1.CUSTOM_MODES_STORAGE_KEY, StorageScope.WORKSPACE);
            if (cachedCustomModes) {
                this.deserializeCachedModes(cachedCustomModes);
            }
        } catch (error) {
            this.logService.error(error, "Failed to load cached custom agents");
        }
    }
    deserializeCachedModes(cachedCustomModes) {
        if (!Array.isArray(cachedCustomModes)) {
            this.logService.error("Invalid cached custom modes data: expected array");
            return;
        }
        for (const cachedMode of cachedCustomModes) {
            if (isCachedChatModeData(cachedMode) && cachedMode.uri) {
                try {
                    const visibility = cachedMode.visibility ?? {
                        userInvocable: true,
                        agentInvocable: cachedMode.infer !== false
                    };
                    if (!visibility.userInvocable) {
                        continue;
                    }
                    const uri = URI.revive(cachedMode.uri);
                    const customChatMode = {
                        uri,
                        name: cachedMode.name,
                        description: cachedMode.description,
                        tools: cachedMode.customTools,
                        model: isString(cachedMode.model) ? [cachedMode.model] : cachedMode.model,
                        argumentHint: cachedMode.argumentHint,
                        agentInstructions: cachedMode.modeInstructions ?? {
                            content: cachedMode.body ?? "",
                            toolReferences: []
                        },
                        handOffs: cachedMode.handOffs,
                        target: cachedMode.target ?? Target.Undefined,
                        visibility,
                        agents: cachedMode.agents,
                        source: reviveChatModeSource(cachedMode.source) ?? {
                            storage: PromptsStorage.local
                        }
                    };
                    const instance = ( new CustomChatMode(customChatMode));
                    this._customModeInstances.set(( uri.toString()), instance);
                } catch (error) {
                    this.logService.error(error, "Failed to revive cached custom agent");
                }
            }
        }
        this.hasCustomModes.set(this._customModeInstances.size > 0);
    }
    saveCachedModes() {
        try {
            const modesToCache = Array.from(( this._customModeInstances.values()));
            this.storageService.store(
                ChatModeService_1.CUSTOM_MODES_STORAGE_KEY,
                modesToCache,
                StorageScope.WORKSPACE,
                StorageTarget.MACHINE
            );
        } catch (error) {
            this.logService.warn("Failed to save cached custom agents", error);
        }
    }
    async refreshCustomPromptModes(fireChangeEvent) {
        try {
            const customModes = await this.promptsService.getCustomAgents(CancellationToken.None);
            const seenUris = ( new Set());
            for (const customMode of customModes) {
                if (!customMode.visibility.userInvocable) {
                    continue;
                }
                const uriString = ( customMode.uri.toString());
                seenUris.add(uriString);
                let modeInstance = this._customModeInstances.get(uriString);
                if (modeInstance) {
                    modeInstance.updateData(customMode);
                } else {
                    modeInstance = ( new CustomChatMode(customMode));
                    this._customModeInstances.set(uriString, modeInstance);
                }
            }
            for (const [uriString] of this._customModeInstances.entries()) {
                if (!( seenUris.has(uriString))) {
                    this._customModeInstances.delete(uriString);
                }
            }
            this.hasCustomModes.set(this._customModeInstances.size > 0);
        } catch (error) {
            this.logService.error(error, "Failed to load custom agents");
            this._customModeInstances.clear();
            this.hasCustomModes.set(false);
        }
        if (fireChangeEvent) {
            this._onDidChangeChatModes.fire();
        }
    }
    getModes() {
        return {
            builtin: this.getBuiltinModes(),
            custom: this.getCustomModes()
        };
    }
    findModeById(id) {
        return this.getBuiltinModes().find(mode => mode.id === id) ?? this._customModeInstances.get(id);
    }
    findModeByName(name) {
        return this.getBuiltinModes().find(mode => mode.name.get() === name) ?? this.getCustomModes().find(mode => mode.name.get() === name);
    }
    getBuiltinModes() {
        const builtinModes = [ChatMode.Ask];
        if (this.chatAgentService.hasToolsAgent || this.isAgentModeDisabledByPolicy()) {
            builtinModes.unshift(ChatMode.Agent);
        }
        builtinModes.push(ChatMode.Edit);
        return builtinModes;
    }
    getCustomModes() {
        return this.chatAgentService.hasToolsAgent || this.isAgentModeDisabledByPolicy() ? Array.from(( this._customModeInstances.values())) : [];
    }
    updateAgentModePolicyContextKey() {
        this.agentModeDisabledByPolicy.set(this.isAgentModeDisabledByPolicy());
    }
    isAgentModeDisabledByPolicy() {
        return this.configurationService.inspect(ChatConfiguration.AgentEnabled).policyValue === false;
    }
};
ChatModeService = ChatModeService_1 = ( __decorate([( __param(0, IPromptsService)), ( __param(1, IChatAgentService)), ( __param(2, IContextKeyService)), ( __param(3, ILogService)), ( __param(4, IStorageService)), ( __param(5, IConfigurationService))], ChatModeService));
function isCachedChatModeData(data) {
    if (typeof data !== "object" || data === null) {
        return false;
    }
    const mode = data;
    return typeof mode.id === "string" && typeof mode.name === "string" && typeof mode.kind === "string" && (mode.description === undefined || typeof mode.description === "string") && (mode.customTools === undefined || Array.isArray(mode.customTools)) && (mode.modeInstructions === undefined || (typeof mode.modeInstructions === "object" && mode.modeInstructions !== null)) && (mode.model === undefined || typeof mode.model === "string" || Array.isArray(mode.model)) && (mode.argumentHint === undefined || typeof mode.argumentHint === "string") && (mode.handOffs === undefined || Array.isArray(mode.handOffs)) && (mode.uri === undefined || (typeof mode.uri === "object" && mode.uri !== null)) && (mode.source === undefined || isChatModeSourceData(mode.source)) && (mode.target === undefined || isTarget(mode.target)) && (mode.visibility === undefined || isCustomAgentVisibility(mode.visibility)) && (mode.agents === undefined || Array.isArray(mode.agents));
}
class CustomChatMode {
    get name() {
        return this._nameObservable;
    }
    get description() {
        return this._descriptionObservable;
    }
    get icon() {
        return constObservable(undefined);
    }
    get isBuiltin() {
        return isBuiltinChatMode(this);
    }
    get customTools() {
        return this._customToolsObservable;
    }
    get model() {
        return this._modelObservable;
    }
    get argumentHint() {
        return this._argumentHintObservable;
    }
    get modeInstructions() {
        return this._modeInstructions;
    }
    get uri() {
        return this._uriObservable;
    }
    get label() {
        return this.name;
    }
    get handOffs() {
        return this._handoffsObservable;
    }
    get source() {
        return this._source;
    }
    get target() {
        return this._targetObservable;
    }
    get visibility() {
        return this._visibilityObservable;
    }
    get agents() {
        return this._agentsObservable;
    }
    constructor(customChatMode) {
        this.kind = ChatModeKind.Agent;
        this.id = ( customChatMode.uri.toString());
        this._nameObservable = observableValue("name", customChatMode.name);
        this._descriptionObservable = observableValue("description", customChatMode.description);
        this._customToolsObservable = observableValue("customTools", customChatMode.tools);
        this._modelObservable = observableValue("model", customChatMode.model);
        this._argumentHintObservable = observableValue("argumentHint", customChatMode.argumentHint);
        this._handoffsObservable = observableValue("handOffs", customChatMode.handOffs);
        this._targetObservable = observableValue("target", customChatMode.target);
        this._visibilityObservable = observableValue("visibility", customChatMode.visibility);
        this._agentsObservable = observableValue("agents", customChatMode.agents);
        this._modeInstructions = observableValue("_modeInstructions", customChatMode.agentInstructions);
        this._uriObservable = observableValue("uri", customChatMode.uri);
        this._source = customChatMode.source;
    }
    updateData(newData) {
        transaction(tx => {
            this._nameObservable.set(newData.name, tx);
            this._descriptionObservable.set(newData.description, tx);
            this._customToolsObservable.set(newData.tools, tx);
            this._modelObservable.set(newData.model, tx);
            this._argumentHintObservable.set(newData.argumentHint, tx);
            this._handoffsObservable.set(newData.handOffs, tx);
            this._targetObservable.set(newData.target, tx);
            this._visibilityObservable.set(newData.visibility, tx);
            this._agentsObservable.set(newData.agents, tx);
            this._modeInstructions.set(newData.agentInstructions, tx);
            this._uriObservable.set(newData.uri, tx);
            this._source = newData.source;
        });
    }
    toJSON() {
        return {
            id: this.id,
            name: this.name.get(),
            description: this.description.get(),
            kind: this.kind,
            customTools: this.customTools.get(),
            model: this.model.get(),
            argumentHint: this.argumentHint.get(),
            modeInstructions: this.modeInstructions.get(),
            uri: this.uri.get(),
            handOffs: this.handOffs.get(),
            source: serializeChatModeSource(this._source),
            target: this.target.get(),
            visibility: this.visibility.get(),
            agents: this.agents.get()
        };
    }
}
function isChatModeSourceData(value) {
    if (typeof value !== "object" || value === null) {
        return false;
    }
    const data = value;
    if (data.storage === PromptsStorage.extension) {
        return typeof data.extensionId === "string";
    }
    if (data.storage === PromptsStorage.plugin) {
        return isUriComponents(data.pluginUri);
    }
    return data.storage === PromptsStorage.local || data.storage === PromptsStorage.user || data.storage === PromptsStorage.internal;
}
function serializeChatModeSource(source) {
    if (!source) {
        return undefined;
    }
    if (source.storage === PromptsStorage.extension) {
        return {
            storage: PromptsStorage.extension,
            extensionId: source.extensionId.value,
            type: source.type
        };
    }
    if (source.storage === PromptsStorage.plugin) {
        return {
            storage: PromptsStorage.plugin,
            pluginUri: source.pluginUri
        };
    }
    return {
        storage: source.storage
    };
}
function reviveChatModeSource(data) {
    if (!data) {
        return undefined;
    }
    if (data.storage === PromptsStorage.extension) {
        return {
            storage: PromptsStorage.extension,
            extensionId: ( new ExtensionIdentifier(data.extensionId)),
            type: data.type ?? ExtensionAgentSourceType.contribution
        };
    }
    if (data.storage === PromptsStorage.plugin) {
        return {
            storage: PromptsStorage.plugin,
            pluginUri: URI.revive(data.pluginUri)
        };
    }
    if (data.storage === PromptsStorage.internal) {
        return {
            storage: PromptsStorage.internal
        };
    }
    return {
        storage: data.storage
    };
}
class BuiltinChatMode {
    constructor(kind, label, description, icon) {
        this.kind = kind;
        this.name = constObservable(kind);
        this.label = constObservable(label);
        this.description = observableValue("description", description);
        this.icon = constObservable(icon);
        this.target = constObservable(Target.Undefined);
    }
    get isBuiltin() {
        return isBuiltinChatMode(this);
    }
    get id() {
        return this.kind;
    }
    toJSON() {
        return {
            id: this.id,
            name: this.name.get(),
            description: this.description.get(),
            kind: this.kind
        };
    }
}
var ChatMode;
(function(ChatMode) {
    ChatMode.Ask = ( new BuiltinChatMode(ChatModeKind.Ask, "Ask", ( localize(7197, "Explore and understand your code")), Codicon.question));
    ChatMode.Edit = ( new BuiltinChatMode(ChatModeKind.Edit, "Edit", ( localize(7198, "Edit or refactor selected code")), Codicon.edit));
    ChatMode.Agent = ( new BuiltinChatMode(ChatModeKind.Agent, "Agent", ( localize(7199, "Describe what to build")), Codicon.agent));
})(ChatMode || (ChatMode = {}));
function isBuiltinChatMode(mode) {
    return mode.id === ChatMode.Ask.id || mode.id === ChatMode.Edit.id || mode.id === ChatMode.Agent.id;
}
function getModeNameForTelemetry(mode) {
    const modeStorage = mode.source?.storage;
    if (modeStorage === PromptsStorage.local || modeStorage === PromptsStorage.user) {
        return String(hash(mode.name.get()));
    }
    return mode.name.get();
}
function getHandoffId(handoff) {
    const slug = handoff.label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
    return `${handoff.agent}:${slug}`;
}
function buildCustomAgentHandoffsInfo(modes) {
    return ( modes.map(mode => {
        const handoffs = mode.handOffs?.get() ?? [];
        const visibility = mode.visibility?.get();
        return {
            id: mode.id,
            name: mode.name.get(),
            isBuiltin: mode.isBuiltin,
            visibility: {
                userInvocable: visibility?.userInvocable ?? true,
                agentInvocable: visibility?.agentInvocable ?? true
            },
            handoffs: ( handoffs.map(h => ({
                id: getHandoffId(h),
                label: h.label,
                agent: h.agent,
                prompt: h.prompt,
                ...(h.send !== undefined ? {
                    send: h.send
                } : {}),
                ...(h.showContinueOn !== undefined ? {
                    showContinueOn: h.showContinueOn
                } : {}),
                ...(h.model !== undefined ? {
                    model: h.model
                } : {})
            })))
        };
    }));
}

export { BuiltinChatMode, ChatMode, ChatModeService, CustomChatMode, buildCustomAgentHandoffsInfo, getHandoffId, getModeNameForTelemetry, isBuiltinChatMode };
