/**
 * Helper Model — lightweight LLM routing for grunt-work tasks.
 *
 * Routes tasks like cache planning, compaction, commit messages, etc. to a
 * cheaper/free model so expensive main models don't waste tokens on routine work.
 *
 * Resolution order:
 *   1. Per-provider helper (helper.providers.{currentProvider}.provider + model)
 *   2. Global helper (helper.globalProvider + helper.globalModel)
 *   3. Tool LLM (tools.llmProvider + tools.llmModel) — if configured
 *   4. Main model (fallback — not a true helper, but ensures the task runs)
 *
 * Design constraints:
 *   - Never throws from HelperModel.chat() — returns empty string on any error
 *   - Logs failures via logger.debug (non-fatal)
 *   - Singleton pattern — import `helperModel` for use
 *   - Tracks token usage separately from the main model
 */
import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
/**
 * HelperRouter — resolves which model to use for a given helper task.
 *
 * Resolution order:
 *   1. Per-provider helper (helper.providers.{currentProvider}.provider + model)
 *   2. Global helper (helper.globalProvider + helper.globalModel)
 *   3. Tool LLM (tools.llmProvider + tools.llmModel) — if configured
 *   4. Main model (fallback — not a true helper, but ensures the task runs)
 */
export class HelperRouter {
    deps;
    constructor(deps) {
        this.deps = deps;
    }
    /**
     * Resolve the best helper for the given task.
     *
     * Returns null only if no provider can be resolved at all.
     */
    resolve(_task) {
        try {
            // 1. Check per-provider helper
            const currentModel = this.deps.providerRegistry.getCurrentModel();
            const currentProviderName = currentModel.provider ?? '';
            // Per-provider helpers stored in config as helper.providers.{name}.provider and .model
            // These are accessed via getCategory since they're nested objects
            const helperConfig = this.deps.configManager.getCategory('helper');
            if (helperConfig) {
                const providers = helperConfig['providers'];
                if (providers && currentProviderName && providers[currentProviderName]) {
                    const perProvider = providers[currentProviderName];
                    if (perProvider.provider && perProvider.model) {
                        try {
                            const provider = this.deps.providerRegistry.get(perProvider.provider);
                            return { provider, modelId: perProvider.model, isHelper: true };
                        }
                        catch {
                            logger.debug(`HelperRouter: per-provider helper ${perProvider.provider} not found, falling through`);
                        }
                    }
                }
            }
            // 2. Global helper
            const globalProvider = this.deps.configManager.get('helper.globalProvider');
            const globalModel = this.deps.configManager.get('helper.globalModel');
            if (globalProvider && globalModel) {
                try {
                    const provider = this.deps.providerRegistry.get(globalProvider);
                    return { provider, modelId: globalModel, isHelper: true };
                }
                catch {
                    logger.debug(`HelperRouter: global helper ${globalProvider} not found, falling through`);
                }
            }
            // 3. Tool LLM
            const toolProvider = this.deps.configManager.get('tools.llmProvider');
            const toolModel = this.deps.configManager.get('tools.llmModel');
            if (toolProvider && toolModel) {
                try {
                    const provider = this.deps.providerRegistry.get(toolProvider);
                    return { provider, modelId: toolModel, isHelper: true };
                }
                catch {
                    logger.debug(`HelperRouter: tool LLM ${toolProvider} not found, falling through`);
                }
            }
            // 4. Fallback to main model
            const mainProvider = this.deps.providerRegistry.getForModel(currentModel.id, currentModel.provider);
            return { provider: mainProvider, modelId: currentModel.id, isHelper: false };
        }
        catch (err) {
            logger.debug('HelperRouter.resolve: failed', { task: _task, error: summarizeError(err) });
            return null;
        }
    }
}
/**
 * HelperModel — lightweight LLM interface for helper tasks.
 *
 * Callers own HelperModel lifetimes explicitly. Never throws — returns empty string on failure.
 * Tracks token usage separately from the main model.
 */
export class HelperModel {
    deps;
    router;
    _usage = { inputTokens: 0, outputTokens: 0, calls: 0 };
    constructor(deps) {
        this.deps = deps;
        this.router = new HelperRouter(deps);
    }
    /**
     * Send a prompt to the helper model for the given task.
     *
     * @param task     The helper task type (for routing).
     * @param prompt   The user prompt to send.
     * @param options  Optional maxTokens, systemPrompt, helperOnly.
     * @returns        The assistant's text response, or empty string on failure.
     */
    async chat(task, prompt, options = {}) {
        // When helper is disabled, skip the resolution chain entirely
        const enabled = this.deps.configManager.get('helper.enabled');
        if (!enabled) {
            if (options.helperOnly)
                return '';
            // Disabled: bypass helper resolution — use main model directly
            try {
                const currentModel = this.deps.providerRegistry.getCurrentModel();
                const mainProvider = this.deps.providerRegistry.getForModel(currentModel.id, currentModel.provider);
                const response = await mainProvider.chat({
                    model: currentModel.id,
                    messages: [{ role: 'user', content: prompt }],
                    maxTokens: options.maxTokens ?? 2048,
                    systemPrompt: options.systemPrompt,
                });
                this._usage.inputTokens += response.usage?.inputTokens ?? 0;
                this._usage.outputTokens += response.usage?.outputTokens ?? 0;
                this._usage.calls += 1;
                return response.content ?? '';
            }
            catch (err) {
                logger.debug('HelperModel.chat: main model fallback failed (non-fatal)', { task, error: summarizeError(err) });
                return '';
            }
        }
        try {
            const resolved = this.router.resolve(task);
            if (!resolved) {
                logger.debug('HelperModel.chat: no provider resolved', { task });
                return '';
            }
            // If helperOnly is set and we fell back to the main model, return empty
            if (options.helperOnly && !resolved.isHelper) {
                return '';
            }
            const response = await resolved.provider.chat({
                model: resolved.modelId,
                messages: [{ role: 'user', content: prompt }],
                maxTokens: options.maxTokens ?? 2048,
                systemPrompt: options.systemPrompt,
            });
            // Track usage
            this._usage.inputTokens += response.usage?.inputTokens ?? 0;
            this._usage.outputTokens += response.usage?.outputTokens ?? 0;
            this._usage.calls += 1;
            logger.debug('HelperModel.chat: success', {
                task,
                isHelper: resolved.isHelper,
                modelId: resolved.modelId,
                inputTokens: response.usage?.inputTokens,
                outputTokens: response.usage?.outputTokens,
            });
            return response.content ?? '';
        }
        catch (err) {
            logger.debug('HelperModel.chat: request failed (non-fatal)', { task, error: summarizeError(err) });
            return '';
        }
    }
    /** Get cumulative helper usage since last reset. */
    getUsage() {
        return { ...this._usage };
    }
    /** Reset usage counters. */
    resetUsage() {
        this._usage = { inputTokens: 0, outputTokens: 0, calls: 0 };
    }
}
