/**
 * Vigthoria Balanced 4B — fast agent path classifier (~0.7–2s on local inference :8016).
 * Regex/trivial detection always wins; LLM router refines ambiguous build prompts only.
 */
const ROUTER_SYSTEM = `You are Vigthoria Agent Router. Reply with ONE JSON object only. No markdown, no HTML, no code fences.

Paths:
- template-instant: single trivial HTML page (hello world, one popup, simple static site) — use Template Service
- v3-agent: multi-file builds, games, refactors, complex implementation
- analysis-only: read-only review/audit/explain, no workspace writes

task_kind: web-build | game-build | implementation | analysis | debugging
fast_path: "template-instant" or null

Example: {"path":"template-instant","task_kind":"web-build","fast_path":"template-instant","confidence":0.95,"reason":"trivial html popup page"}`;
const INFERENCE_MODEL_IDS = [
    'vigthoria-balanced-4b',
    'vigthoria-v3-balanced-4b',
];
function normalizePath(value) {
    const p = String(value || '').trim().toLowerCase();
    if (p === 'template-instant' || p === 'template' || p === 'html-template') {
        return 'template-instant';
    }
    if (p === 'analysis-only' || p === 'analysis') {
        return 'analysis-only';
    }
    if (p === 'v3-agent' || p === 'v3' || p === 'agent') {
        return 'v3-agent';
    }
    return null;
}
export function parseBalancedRouterJson(raw) {
    const text = String(raw || '').trim();
    if (!text)
        return null;
    const start = text.indexOf('{');
    if (start < 0)
        return null;
    let depth = 0;
    for (let i = start; i < text.length; i += 1) {
        if (text[i] === '{')
            depth += 1;
        if (text[i] === '}') {
            depth -= 1;
            if (depth === 0) {
                try {
                    return JSON.parse(text.slice(start, i + 1));
                }
                catch {
                    return null;
                }
            }
        }
    }
    return null;
}
/**
 * Inference bases for Balanced 4B routing only.
 * Local developer machines must opt in (env) — avoids ~1.5s localhost probe on every Windows turn.
 */
export function getInferenceRouterBaseUrls(selfHostedUrl) {
    const urls = [
        process.env.VIGTHORIA_INFERENCE_URL,
        process.env.VIGTHORIA_SELF_HOSTED_MODELS_API_URL,
        selfHostedUrl,
    ].filter(Boolean).map((u) => String(u).replace(/\/$/, ''));
    const allowLocalhost = process.env.VIGTHORIA_ENABLE_LOCAL_INFERENCE_ROUTER === '1'
        || process.env.VIGTHORIA_AGENT_LLM_ROUTER === '1'
        || process.platform === 'linux';
    if (allowLocalhost) {
        urls.push('http://127.0.0.1:8016');
    }
    return [...new Set(urls)];
}
let inferenceHealthCache = null;
function modelIdsFromPayload(payload) {
    if (!payload || typeof payload !== 'object')
        return [];
    const body = payload;
    const values = [
        body.available_models,
        body.loaded_models,
        body.models,
        body.data,
    ].filter(Array.isArray).flat();
    return values.map((entry) => {
        if (typeof entry === 'string')
            return entry;
        if (entry && typeof entry === 'object') {
            const model = entry;
            return String(model.id || model.model || model.name || '');
        }
        return '';
    }).filter(Boolean);
}
function includesBalancedRouterModel(modelIds) {
    const allowed = new Set(INFERENCE_MODEL_IDS);
    return modelIds.some((id) => allowed.has(String(id).trim().toLowerCase().replace(/:latest$/, '')));
}
async function probeBalancedRouterBase(base, timeoutMs) {
    const fetchJson = async (path) => {
        const controller = new AbortController();
        const timer = setTimeout(() => controller.abort(), timeoutMs);
        try {
            const response = await fetch(`${base}${path}`, { signal: controller.signal });
            const payload = await response.json().catch(() => null);
            return { ok: response.ok, payload };
        }
        catch {
            return { ok: false, payload: null };
        }
        finally {
            clearTimeout(timer);
        }
    };
    const health = await fetchJson('/health');
    if (!health.ok)
        return false;
    const advertisedByHealth = modelIdsFromPayload(health.payload);
    if (advertisedByHealth.length > 0) {
        return includesBalancedRouterModel(advertisedByHealth);
    }
    // Older inference nodes only expose capabilities on /v1/models.
    const catalog = await fetchJson('/v1/models');
    return catalog.ok && includesBalancedRouterModel(modelIdsFromPayload(catalog.payload));
}
async function compatibleInferenceRouterBases(selfHostedUrl, timeoutMs) {
    const bases = getInferenceRouterBaseUrls(selfHostedUrl);
    const key = bases.join('|');
    const now = Date.now();
    if (inferenceHealthCache
        && inferenceHealthCache.key === key
        && now - inferenceHealthCache.checkedAt < 60_000) {
        return inferenceHealthCache.compatibleBases;
    }
    const compatibleBases = [];
    for (const base of bases) {
        if (await probeBalancedRouterBase(base, timeoutMs)) {
            compatibleBases.push(base);
        }
    }
    inferenceHealthCache = { key, compatibleBases, checkedAt: now };
    return compatibleBases;
}
export async function isFastInferenceRouterAvailable(selfHostedUrl, timeoutMs = 400) {
    if (process.env.VIGTHORIA_AGENT_LLM_ROUTER === '0') {
        return false;
    }
    return (await compatibleInferenceRouterBases(selfHostedUrl, timeoutMs)).length > 0;
}
export async function routeWithBalanced4b(prompt, selfHostedUrl, options = {}) {
    const timeoutMs = options.timeoutMs ?? Number.parseInt(process.env.VIGTHORIA_AGENT_ROUTER_TIMEOUT_MS || '8000', 10);
    const bases = await compatibleInferenceRouterBases(selfHostedUrl, Math.min(timeoutMs, 1500));
    let lastError = 'Inference router unreachable';
    if (bases.length === 0) {
        return { ok: false, error: 'No compatible Balanced 4B inference endpoint is available' };
    }
    for (const base of bases) {
        const started = Date.now();
        for (const model of INFERENCE_MODEL_IDS) {
            const controller = new AbortController();
            const timer = setTimeout(() => controller.abort(), timeoutMs);
            try {
                const response = await fetch(`${base}/v1/chat/completions`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        model,
                        messages: [
                            { role: 'system', content: ROUTER_SYSTEM },
                            { role: 'user', content: String(prompt || '').slice(0, 1200) },
                        ],
                        max_tokens: 96,
                        temperature: 0,
                        stream: false,
                    }),
                    signal: controller.signal,
                });
                const payload = await response.json().catch(() => null);
                if (!response.ok) {
                    lastError = `HTTP ${response.status} from ${base}`;
                    continue;
                }
                const raw = payload?.choices?.[0]?.message?.content || '';
                const parsed = parseBalancedRouterJson(raw);
                if (!parsed) {
                    lastError = 'Router returned non-JSON';
                    continue;
                }
                return {
                    ok: true,
                    raw,
                    parsed,
                    latencyMs: Date.now() - started,
                    model,
                    endpoint: base,
                };
            }
            catch (err) {
                lastError = err instanceof Error ? err.message : String(err);
            }
            finally {
                clearTimeout(timer);
            }
        }
    }
    return { ok: false, error: lastError };
}
export function shouldUseBalancedRouter(prompt, regexTaskKind = '') {
    if (process.env.VIGTHORIA_AGENT_LLM_ROUTER === '0') {
        return false;
    }
    const kind = String(regexTaskKind || '').toLowerCase();
    // Regex already resolved clear build families — LLM must not override (e.g. landing → implementation).
    if (kind === 'web-build' || kind === 'game-build') {
        return false;
    }
    const text = String(prompt || '').trim();
    if (text.length > 700 || text.length < 12) {
        return false;
    }
    return true;
}
