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 __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { injectable, inject } from 'tsyringe';
import { AgentFeature } from '../../../../domain/generated/output.js';
import { StructuredCallError } from '../../../../application/ports/output/agents/structured-call-error.js';
import { getSettings } from '../../settings.service.js';
/**
 * Structured agent caller that abstracts native structured output vs prompt-based JSON extraction.
 *
 * Uses the agent's native structured output capability when available,
 * otherwise falls back to prompt-based JSON extraction with brace-depth parsing.
 */
let StructuredAgentCallerService = class StructuredAgentCallerService {
    executorProvider;
    executorFactory;
    constructor(executorProvider, executorFactory) {
        this.executorProvider = executorProvider;
        this.executorFactory = executorFactory;
    }
    async call(prompt, schema, options) {
        let executor;
        if (options?.agentType) {
            const settings = getSettings();
            executor = this.executorFactory.createExecutor(options.agentType, settings.agent);
        }
        else {
            executor = await this.executorProvider.getExecutor();
        }
        if (executor.supportsFeature(AgentFeature.structuredOutput)) {
            return this.callWithNativeSchema(executor, prompt, schema, options);
        }
        return this.callWithPromptFallback(executor, prompt, schema, options);
    }
    // Native structured output path
    async callWithNativeSchema(executor, prompt, schema, options) {
        const result = await executor.execute(prompt, { ...options, outputSchema: schema });
        const structured = result.metadata?.structured_output;
        if (structured != null)
            return structured;
        return this.parseJsonFromText(result.result);
    }
    // Prompt-based fallback path
    async callWithPromptFallback(executor, prompt, schema, options) {
        const wrappedPrompt = this.wrapPromptWithJsonInstructions(prompt, schema);
        const result = await executor.execute(wrappedPrompt, options);
        return this.parseJsonFromText(result.result);
    }
    wrapPromptWithJsonInstructions(prompt, schema) {
        return `${prompt}

IMPORTANT: You MUST respond with ONLY a JSON object matching this schema. No markdown fences, no explanation, no extra text.

JSON Schema:
${JSON.stringify(schema, null, 2)}

Return ONLY the JSON object.`;
    }
    // Extract first JSON object from text using brace-depth tracking
    parseJsonFromText(text) {
        const start = text.indexOf('{');
        if (start === -1) {
            throw new StructuredCallError('No JSON object found in agent response', 'parse_failed');
        }
        let depth = 0;
        let inString = false;
        for (let i = start; i < text.length; i++) {
            const ch = text[i];
            if (inString) {
                if (ch === '\\') {
                    i++; // skip escaped character
                }
                else if (ch === '"') {
                    inString = false;
                }
                continue;
            }
            if (ch === '"') {
                inString = true;
            }
            else if (ch === '{') {
                depth++;
            }
            else if (ch === '}') {
                depth--;
                if (depth === 0) {
                    const jsonStr = text.substring(start, i + 1);
                    try {
                        return JSON.parse(jsonStr);
                    }
                    catch (err) {
                        throw new StructuredCallError('Failed to parse JSON from agent response', 'parse_failed', err);
                    }
                }
            }
        }
        throw new StructuredCallError('Incomplete JSON object in agent response', 'parse_failed');
    }
};
StructuredAgentCallerService = __decorate([
    injectable(),
    __param(0, inject('IAgentExecutorProvider')),
    __param(1, inject('IAgentExecutorFactory')),
    __metadata("design:paramtypes", [Object, Object])
], StructuredAgentCallerService);
export { StructuredAgentCallerService };
