
import { __decorate, __param } from '../../../../../../../../external/tslib/tslib.es6.js';
import { Position } from '../../../../../editor/common/core/position.js';
import { Range } from '../../../../../editor/common/core/range.js';
import { OffsetRange } from '../../../../../editor/common/core/ranges/offsetRange.js';
import { IChatVariablesService } from '../attachments/chatVariables.service.js';
import { ChatAgentLocation, ChatModeKind } from '../constants.js';
import { IChatAgentService } from '../participants/chatAgents.service.js';
import { IChatSlashCommandService } from '../participants/chatSlashCommands.service.js';
import { IPromptsService } from '../promptSyntax/service/promptsService.service.js';
import { isToolSet } from '../tools/languageModelToolsService.js';
import { chatVariableLeader, chatAgentLeader, chatSubcommandLeader, ChatRequestTextPart, ChatRequestAgentPart, ChatRequestToolPart, ChatRequestToolSetPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestSlashPromptPart, ChatRequestDynamicVariablePart } from './chatParserTypes.js';

const agentReg = /^@([\w_\-\.]+)(?=(\s|$|\b))/i;
const variableReg = /^#([\w_\-]+)(:\d+)?(?=(\s|$|\b))/i;
const slashReg = /^\/([\p{L}\d_\-\.:]+)(?=(\s|$|\b))/iu;
let ChatRequestParser = class ChatRequestParser {
    constructor(agentService, variableService, slashCommandService, promptsService) {
        this.agentService = agentService;
        this.variableService = variableService;
        this.slashCommandService = slashCommandService;
        this.promptsService = promptsService;
    }
    parseChatRequest(sessionResource, message, location = ChatAgentLocation.Chat, context) {
        const references = this.variableService.getDynamicVariables(sessionResource);
        const selectedToolAndToolSets = this.variableService.getSelectedToolAndToolSets(sessionResource);
        return this.parseChatRequestWithReferences(references, selectedToolAndToolSets, message, location, context);
    }
    parseChatRequestWithReferences(
        references,
        selectedToolAndToolSets,
        message,
        location = ChatAgentLocation.Chat,
        context
    ) {
        const parts = [];
        const toolsByName = ( new Map());
        const toolSetsByName = ( new Map());
        for (const [entry, enabled] of selectedToolAndToolSets) {
            if (enabled) {
                if (isToolSet(entry)) {
                    toolSetsByName.set(entry.referenceName, entry);
                } else {
                    toolsByName.set(entry.toolReferenceName ?? entry.displayName, entry);
                }
            }
        }
        let lineNumber = 1;
        let column = 1;
        for (let i = 0; i < message.length; i++) {
            const previousChar = message.charAt(i - 1);
            const char = message.charAt(i);
            let newPart;
            if (previousChar.match(/\s/) || i === 0) {
                if (char === chatVariableLeader) {
                    newPart = this.tryToParseVariable(message.slice(i), i, ( new Position(lineNumber, column)), parts, toolsByName, toolSetsByName);
                } else if (char === chatAgentLeader) {
                    newPart = this.tryToParseAgent(message.slice(i), message, i, ( new Position(lineNumber, column)), parts, location, context);
                } else if (char === chatSubcommandLeader) {
                    newPart = this.tryToParseSlashCommand(message.slice(i), message, i, ( new Position(lineNumber, column)), parts, location, context);
                }
                if (!newPart) {
                    newPart = this.tryToParseDynamicVariable(message.slice(i), i, ( new Position(lineNumber, column)), references);
                }
            }
            if (newPart) {
                if (i !== 0) {
                    const previousPart = parts.at(-1);
                    const previousPartEnd = previousPart?.range.endExclusive ?? 0;
                    const previousPartEditorRangeEndLine = previousPart?.editorRange.endLineNumber ?? 1;
                    const previousPartEditorRangeEndCol = previousPart?.editorRange.endColumn ?? 1;
                    parts.push(( new ChatRequestTextPart(( new OffsetRange(previousPartEnd, i)), ( new Range(
                        previousPartEditorRangeEndLine,
                        previousPartEditorRangeEndCol,
                        lineNumber,
                        column
                    )), message.slice(previousPartEnd, i))));
                }
                parts.push(newPart);
            }
            if (char === "\n") {
                lineNumber++;
                column = 1;
            } else {
                column++;
            }
        }
        const lastPart = parts.at(-1);
        const lastPartEnd = lastPart?.range.endExclusive ?? 0;
        if (lastPartEnd < message.length) {
            parts.push(( new ChatRequestTextPart(( new OffsetRange(lastPartEnd, message.length)), ( new Range(
                lastPart?.editorRange.endLineNumber ?? 1,
                lastPart?.editorRange.endColumn ?? 1,
                lineNumber,
                column
            )), message.slice(lastPartEnd, message.length))));
        }
        return {
            parts,
            text: message
        };
    }
    tryToParseAgent(message, fullMessage, offset, position, parts, location, context) {
        const nextAgentMatch = message.match(agentReg);
        if (!nextAgentMatch) {
            return;
        }
        const [full, name] = nextAgentMatch;
        const agentRange = ( new OffsetRange(offset, offset + full.length));
        const agentEditorRange = ( new Range(
            position.lineNumber,
            position.column,
            position.lineNumber,
            position.column + full.length
        ));
        let agents = this.agentService.getAgentsByName(name);
        if (!agents.length) {
            const fqAgent = this.agentService.getAgentByFullyQualifiedId(name);
            if (fqAgent) {
                agents = [fqAgent];
            }
        }
        const agent = agents.length > 1 && context?.selectedAgent ? context.selectedAgent : agents.find(a => a.locations.includes(location));
        if (!agent) {
            return;
        }
        if (context?.mode && !agent.modes.includes(context.mode)) {
            return;
        }
        if (( parts.some(p => p instanceof ChatRequestAgentPart))) {
            return;
        }
        if (( parts.some(
            p => (p instanceof ChatRequestTextPart && p.text.trim() !== "") || !(p instanceof ChatRequestAgentPart)
        ))) {
            return;
        }
        const previousPart = parts.at(-1);
        const previousPartEnd = previousPart?.range.endExclusive ?? 0;
        const textSincePreviousPart = fullMessage.slice(previousPartEnd, offset);
        if (textSincePreviousPart.trim() !== "") {
            return;
        }
        return ( new ChatRequestAgentPart(agentRange, agentEditorRange, agent));
    }
    tryToParseVariable(message, offset, position, parts, toolsByName, toolSetsByName) {
        const nextVariableMatch = message.match(variableReg);
        if (!nextVariableMatch) {
            return;
        }
        const [full, name] = nextVariableMatch;
        const varRange = ( new OffsetRange(offset, offset + full.length));
        const varEditorRange = ( new Range(
            position.lineNumber,
            position.column,
            position.lineNumber,
            position.column + full.length
        ));
        const tool = toolsByName.get(name);
        if (tool) {
            return ( new ChatRequestToolPart(varRange, varEditorRange, name, tool.id, tool.displayName, tool.icon));
        }
        const toolset = toolSetsByName.get(name);
        if (toolset) {
            const value = ( Array.from(toolset.getTools()).map(t => ( new ChatRequestToolPart(
                varRange,
                varEditorRange,
                t.toolReferenceName ?? t.displayName,
                t.id,
                t.displayName,
                t.icon
            )).toVariableEntry()));
            return ( new ChatRequestToolSetPart(
                varRange,
                varEditorRange,
                toolset.id,
                toolset.referenceName,
                toolset.icon,
                value
            ));
        }
        return;
    }
    tryToParseSlashCommand(remainingMessage, fullMessage, offset, position, parts, location, context) {
        const nextSlashMatch = remainingMessage.match(slashReg);
        if (!nextSlashMatch) {
            return;
        }
        if (( parts.some(
            p => !(p instanceof ChatRequestAgentPart) && !(p instanceof ChatRequestTextPart && p.text.trim() === "")
        ))) {
            return;
        }
        const previousPart = parts.at(-1);
        const previousPartEnd = previousPart?.range.endExclusive ?? 0;
        const textSincePreviousPart = fullMessage.slice(previousPartEnd, offset);
        if (textSincePreviousPart.trim() !== "") {
            return;
        }
        const [full, command] = nextSlashMatch;
        const slashRange = ( new OffsetRange(offset, offset + full.length));
        const slashEditorRange = ( new Range(
            position.lineNumber,
            position.column,
            position.lineNumber,
            position.column + full.length
        ));
        const usedAgent = parts.find(p => p instanceof ChatRequestAgentPart)?.agent ?? (context?.forcedAgent ? context.forcedAgent : undefined);
        if (usedAgent) {
            const subCommand = usedAgent.slashCommands.find(c => c.name === command);
            if (subCommand) {
                return ( new ChatRequestAgentSubcommandPart(slashRange, slashEditorRange, subCommand));
            }
        }
        const capabilities = context?.attachmentCapabilities ?? usedAgent?.capabilities;
        const slashCommands = this.slashCommandService.getCommands(location, context?.mode ?? ChatModeKind.Ask);
        const slashCommand = slashCommands.find(c => c.command === command);
        if (!usedAgent || slashCommand?.silent || capabilities?.supportsPromptAttachments) {
            if (slashCommand) {
                return ( new ChatRequestSlashCommandPart(slashRange, slashEditorRange, slashCommand));
            } else {
                const defaultAgent = this.agentService.getDefaultAgent(location, context?.mode);
                const subCommand = defaultAgent?.slashCommands.find(c => c.name === command);
                if (subCommand) {
                    return ( new ChatRequestAgentSubcommandPart(slashRange, slashEditorRange, subCommand));
                }
            }
            const isPromptCommand = this.promptsService.isValidSlashCommandName(command);
            if (isPromptCommand) {
                return ( new ChatRequestSlashPromptPart(slashRange, slashEditorRange, command));
            }
        }
        return;
    }
    tryToParseDynamicVariable(message, offset, position, references) {
        const refAtThisPosition = references.find(
            r => r.range.startLineNumber === position.lineNumber && r.range.startColumn === position.column
        );
        if (refAtThisPosition) {
            const length = refAtThisPosition.range.endColumn - refAtThisPosition.range.startColumn;
            const text = message.substring(0, length);
            const range = ( new OffsetRange(offset, offset + length));
            return ( new ChatRequestDynamicVariablePart(
                range,
                refAtThisPosition.range,
                text,
                refAtThisPosition.id,
                refAtThisPosition.modelDescription,
                refAtThisPosition.data,
                refAtThisPosition.fullName,
                refAtThisPosition.icon,
                refAtThisPosition.isFile,
                refAtThisPosition.isDirectory
            ));
        }
        return;
    }
};
ChatRequestParser = ( __decorate([( __param(0, IChatAgentService)), ( __param(1, IChatVariablesService)), ( __param(2, IChatSlashCommandService)), ( __param(3, IPromptsService))], ChatRequestParser));

export { ChatRequestParser };
