"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var SessionInputContextService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SessionInputContextService = void 0;
const common_1 = require("@nestjs/common");
const context_generation_service_1 = require("../context-generation/context-generation.service");
const application_state_service_1 = require("../application-state/application-state.service");
const context_snippets_service_1 = require("../context-snippets/context-snippets.service");
const gpt_tokenizer_1 = require("gpt-tokenizer");
const custom_variables_service_1 = require("../custom-variables/custom-variables.service");
let SessionInputContextService = SessionInputContextService_1 = class SessionInputContextService {
    constructor(contextGenerationService, applicationStateService, contextSnippetsService, customVariablesService) {
        this.contextGenerationService = contextGenerationService;
        this.applicationStateService = applicationStateService;
        this.contextSnippetsService = contextSnippetsService;
        this.customVariablesService = customVariablesService;
        this.logger = new common_1.Logger(SessionInputContextService_1.name);
    }
    async resolveContextSnippets(prompt) {
        const snippetRegex = /(^|\s)\!(\w[-\w]*)(?=\s|$)/g;
        const matches = [...prompt.matchAll(snippetRegex)];
        if (matches.length === 0) {
            return { resolvedContent: '', cleanedPrompt: prompt };
        }
        const snippetHandles = matches.map((match) => match[2]);
        this.logger.log(`Found context snippet handles: ${snippetHandles.join(', ')}`);
        const resolvedContents = [];
        for (const handle of snippetHandles) {
            try {
                const snippet = await this.contextSnippetsService.findByHandle(handle);
                const content = await this.contextGenerationService.render(snippet.template_content, {});
                resolvedContents.push(content);
            }
            catch (error) {
                this.logger.error(`Failed to resolve context snippet "!${handle}": ${error.message}`);
                resolvedContents.push(`Error resolving !${handle}: ${error.message}`);
            }
        }
        const cleanedPrompt = prompt
            .replace(/(^|\s)\!(\w[-\w]*)(?=\s|$)/g, '$1$2')
            .replace(/\s{2,}/g, ' ')
            .trim();
        return {
            resolvedContent: resolvedContents.join('\n\n'),
            cleanedPrompt,
        };
    }
    async generateContext(dto, contextTemplate, previousActionsSummary) {
        const { resolvedContent: context_snippets_content, cleanedPrompt } = await this.resolveContextSnippets(dto.user_prompt);
        dto.user_prompt = cleanedPrompt;
        this.logger.log(`Generating context. Template: ${contextTemplate?.template_name || 'None'}. Ad-hoc: ${!!dto.ad_hoc_context_definition}. Snippets: ${context_snippets_content.length > 0 ? 'Yes' : 'No'}.`);
        const defaultTemplate = `<%~ it.context_snippets_content %>

<%~ it.adhoc_files_content %>

<%~ it.adhoc_folders_content %>

<%~ it.adhoc_command_outputs_content %>

<%~ it.user_input %>`;
        const templateContent = contextTemplate?.template_content ?? defaultTemplate;
        if (templateContent.trim() === '') {
            this.logger.warn('Context template is empty. Using only the user prompt.');
            return dto.user_prompt;
        }
        const adHocData = {
            adhoc_files_content: '',
            adhoc_folders_content: '',
            adhoc_command_outputs_content: '',
        };
        let templateContextDef = {};
        if (contextTemplate?.context_definition) {
            try {
                templateContextDef = JSON.parse(contextTemplate.context_definition);
            }
            catch (e) {
                this.logger.warn(`Could not parse context_definition from template ID ${contextTemplate.id}`);
            }
        }
        let adhocContextDef = {};
        if (dto.ad_hoc_context_definition) {
            try {
                adhocContextDef = JSON.parse(dto.ad_hoc_context_definition);
            }
            catch (e) {
                this.logger.warn(`Could not parse ad_hoc_context_definition as JSON: ${dto.ad_hoc_context_definition}`);
            }
        }
        const mergedFiles = [
            ...(templateContextDef.files || []),
            ...(adhocContextDef.files || []),
        ];
        const uniqueFiles = [...new Set(mergedFiles)];
        const mergedFolders = [
            ...(templateContextDef.folders || []),
            ...(adhocContextDef.folders || []),
        ];
        const uniqueFolders = [...new Set(mergedFolders)];
        if (uniqueFiles.length > 0) {
            const fileContents = await Promise.all(uniqueFiles.map((filePath) => this.contextGenerationService.secureReadFile(filePath)));
            adHocData.adhoc_files_content = fileContents.join('\n\n');
        }
        if (uniqueFolders.length > 0) {
            const folderContexts = await Promise.all(uniqueFolders.map(async (folderPath) => {
                const tree = await this.contextGenerationService.secureTree(folderPath);
                const header = `// Tree for: ${folderPath}\n\`\`\`\n${tree}\n\`\`\``;
                const filesInFolder = await this.contextGenerationService.secureGlob(`${folderPath}/**/*`);
                const fileContents = await Promise.all(filesInFolder.map((filePath) => this.contextGenerationService.secureReadFile(filePath)));
                return [header, ...fileContents].join('\n\n');
            }));
            adHocData.adhoc_folders_content = folderContexts.join('\n\n---\n\n');
        }
        if (adhocContextDef.command_outputs &&
            adhocContextDef.command_outputs.length > 0) {
            adHocData.adhoc_command_outputs_content = adhocContextDef.command_outputs
                .map((output) => `// Command Output:\n\`\`\`\n${output}\n\`\`\``)
                .join('\n\n');
        }
        const enabledVariables = await this.customVariablesService.findAllEnabled();
        const variableMap = enabledVariables.reduce((acc, curr) => {
            acc[curr.key] = curr.value;
            return acc;
        }, {});
        const data = {
            ad_hoc_context_definition: dto.ad_hoc_context_definition || null,
            user_input: dto.user_prompt,
            user_prev_action: previousActionsSummary || '',
            context_snippets_content,
            ...adHocData,
            VAR: variableMap,
        };
        try {
            const generatedString = await this.contextGenerationService.render(templateContent, data);
            const tokenCount = (0, gpt_tokenizer_1.countTokens)(generatedString);
            const TOKEN_LIMIT = await this.applicationStateService.getContextTokenLimit();
            if (tokenCount > TOKEN_LIMIT) {
                const errorMessage = `The context you requested is too large (${tokenCount} tokens, limit is ${TOKEN_LIMIT}). Please ask for a smaller context.`;
                this.logger.warn(`Generated context exceeds token limit. Size: ${tokenCount} tokens. Limit: ${TOKEN_LIMIT} tokens.`);
                return errorMessage;
            }
            if (!templateContent.includes('it.user_input')) {
                this.logger.warn("Template does not explicitly use 'it.user_input'. Appending user prompt to the end.");
                return generatedString.trim()
                    ? `${generatedString}\n\n${dto.user_prompt}`
                    : dto.user_prompt;
            }
            this.logger.log(`Generated context string of length ${generatedString.length} (${tokenCount} tokens)`);
            return generatedString;
        }
        catch (error) {
            this.logger.error(`Context generation failed: ${error.message}`, error.stack);
            throw new common_1.BadRequestException(`Failed to generate context from template: ${error.message}`);
        }
    }
};
exports.SessionInputContextService = SessionInputContextService;
exports.SessionInputContextService = SessionInputContextService = SessionInputContextService_1 = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [context_generation_service_1.ContextGenerationService,
        application_state_service_1.ApplicationStateService,
        context_snippets_service_1.ContextSnippetsService,
        custom_variables_service_1.CustomVariablesService])
], SessionInputContextService);
//# sourceMappingURL=session-input-context.service.js.map