/**
 * 임베딩 모델 자동 감지 부트스트랩 — 하이브리드(sparse+dense) 검색 온보딩.
 *
 * 문제: g1nation.embeddingModel 기본값이 '' (비활성) — LM Studio 에 임베딩 모델이
 * 로드돼 있어도 사용자가 설정 키와 모델명 문자열을 알아야만 켜진다. 비개발자
 * 사용자에게는 사실상 영구 비활성. 측정 결과 임베딩 블렌드가 어휘 갭
 * ("심판"↔"LLM-as-a-Judge" 류 동의어/패러프레이즈) miss 를 해소하므로 기본 ON 가치가 있다.
 *
 * 해결: 활성화 시 embeddingModel 이 비어 있으면 엔진(ollamaUrl)의 모델 목록을 조회해
 * 이름에 'embed' 가 들어간 모델을 찾아 자동 설정 + 1회 알림 ("전체 색인" 버튼 포함).
 *
 * 보호 장치:
 *  - 이미 embeddingModel 설정됨 → no-op (기존 사용자 무영향).
 *  - 자동 설정 이력이 있는데 현재 비어 있음 = 사용자가 의도적으로 껐다 → 재설정 안 함.
 *  - 엔진 미응답/임베딩 모델 없음 → 조용히 skip (다음 활성화 때 재시도).
 */
import * as vscode from 'vscode';
import { logError, logInfo } from '../utils';

const STATE_KEY = 'astra.embeddingAutoConfigured';
const PROBE_TIMEOUT_MS = 4000;

/** 엔진의 모델 목록에서 임베딩 모델 id 를 찾는다 (LM Studio /v1/models · Ollama /api/tags). */
async function detectEmbeddingModel(baseUrl: string): Promise<string | null> {
    const root = baseUrl.replace(/\/+$/, '');
    const tryFetch = async (url: string): Promise<any | null> => {
        const controller = new AbortController();
        const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
        try {
            const r = await fetch(url, { signal: controller.signal });
            return r.ok ? await r.json() : null;
        } catch { return null; } finally { clearTimeout(timer); }
    };
    // OpenAI-호환 (LM Studio) 우선, 실패 시 Ollama.
    const v1 = await tryFetch(`${root}/v1/models`);
    let ids: string[] = Array.isArray(v1?.data) ? v1.data.map((m: any) => String(m?.id || '')) : [];
    if (ids.length === 0) {
        const tags = await tryFetch(`${root}/api/tags`);
        ids = Array.isArray(tags?.models) ? tags.models.map((m: any) => String(m?.name || '')) : [];
    }
    // 임베딩 모델 후보 — 'embed' 외에 대표 임베딩 계열 이름도 포착
    // (multilingual-e5-small, bge-m3 등은 이름에 'embed' 가 없다).
    const candidates = ids.filter(id => /embed|(^|[^a-z0-9])(bge|gte|e5)([^a-z0-9]|$)|minilm|arctic-embed/i.test(id));
    if (candidates.length === 0) return null;
    // 한국어 두뇌 특성상 다국어 모델 우선 (골든셋 측정: nomic 은 한국어 동의어 매칭 한계).
    const rank = (id: string) => (/multilingual|bge-m3|e5/i.test(id) ? 0 : 1);
    candidates.sort((a, b) => rank(a) - rank(b));
    return candidates[0];
}

/**
 * embeddingModel 미설정 시 엔진에서 임베딩 모델을 자동 감지해 설정한다.
 * 활성화 초기에 1회 호출 (fire-and-forget — 검색은 TF-IDF 로 이미 동작 중).
 */
export async function ensureEmbeddingConfigured(context: vscode.ExtensionContext): Promise<void> {
    try {
        const cfg = vscode.workspace.getConfiguration('g1nation');
        const current = (cfg.get<string>('embeddingModel', '') || '').trim();
        if (current) return; // 이미 설정됨
        if (context.globalState.get<boolean>(STATE_KEY)) return; // 사용자가 의도적으로 비움

        const baseUrl = (cfg.get<string>('ollamaUrl', '') || 'http://127.0.0.1:1234').trim();
        const model = await detectEmbeddingModel(baseUrl);
        if (!model) { logInfo('Embedding bootstrap: 엔진에서 임베딩 모델 미발견 — skip.', { baseUrl }); return; }

        await cfg.update('embeddingModel', model, vscode.ConfigurationTarget.Global);
        await context.globalState.update(STATE_KEY, true);
        logInfo('Embedding bootstrap: 하이브리드 검색 자동 활성화.', { model, baseUrl });

        void vscode.window.showInformationMessage(
            `Astra: 임베딩 모델 "${model}" 을 발견해 하이브리드 검색을 켰습니다. ` +
            '전체 색인을 한 번 실행하면 즉시 전체 두뇌에 적용됩니다 (이후는 자동 증분).',
            '지금 전체 색인',
        ).then(pick => {
            if (pick === '지금 전체 색인') void vscode.commands.executeCommand('g1nation.embeddings.backfill');
        });
    } catch (e: any) {
        logError('Embedding bootstrap 실패 (TF-IDF 검색은 정상 동작).', { error: e?.message ?? String(e) });
    }
}
