package main

import (
	"context"
	"log/slog"
	"sync"
	"time"

	"fiko-ai/config"
	"fiko-ai/internal/llm"
	"fiko-ai/internal/skill"
)

// backfillTimeout açılıştaki embedding doldurmanın üst sınırı; sunucu açılışını asla beklemez (arka planda çalışır).
const backfillTimeout = 5 * time.Minute

// prewarmTimeout embedding modelini belleğe yükleyen ısıtma çağrısının üst sınırı.
const prewarmTimeout = 2 * time.Minute

// setupSkillEmbedding OLLAMA_EMBED_MODEL verilmişse embedding'i etkinleştirir ve embedding'i eksik
// skill'leri arka planda doldurur. Dönen fonksiyon doldurmayı iptal edip bitmesini bekler:
// Mongo bağlantısı kapanırken yarım kalmış bir yazma olmasın diye `defer` ile çağrılmalıdır.
// Model verilmemişse embedding kapalıdır; skill araması anahtar kelimeyle çalışır (bilinçli düşüş).
func setupSkillEmbedding(ctx context.Context, svc *skill.Service, emb llm.Embedder, cfg config.Config, log *slog.Logger) func() {
	if cfg.Ollama.EmbedModel == "" {
		log.Info("skill embedding kapalı (OLLAMA_EMBED_MODEL boş): arama yalnızca anahtar kelimeyle çalışır")
		return func() {}
	}
	svc.SetEmbedder(emb)
	log.Info("skill embedding etkin", "model", cfg.Ollama.EmbedModel)

	// **Model ısıtma (pre-warm).** Embedding modelleri ilk çağrıda belleğe yüklenir;
	// qwen3-embedding (4.6 GB) için bu 30 saniyeyi aşabiliyor ve OLLAMA_REQUEST_TIMEOUT'a
	// takılıp kullanıcının ilk araması 504 ile ölüyordu (ölçüm sırasında yakalandı).
	// Isıtma ARKA PLANDA yapılır: sunucu açılışını beklemez, ama kullanıcı ilk aramayı
	// yaptığında model hazırdır. Başarısız olursa yalnızca uyarır (arama anahtar kelimeye düşer).
	go func() {
		wctx, wcancel := context.WithTimeout(ctx, prewarmTimeout)
		defer wcancel()
		start := time.Now()
		if _, err := emb.Embed(wctx, "fiko hazır"); err != nil {
			log.Warn("embedding modeli ısıtılamadı (ilk arama yavaş olabilir)", "err", err)
			return
		}
		log.Info("embedding modeli ısıtıldı", "sure", time.Since(start).Round(time.Millisecond))
	}()

	bctx, cancel := context.WithTimeout(ctx, backfillTimeout)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		rep, err := svc.Reindex(bctx, false)
		switch {
		case err != nil && bctx.Err() != nil:
			log.Info("skill embedding doldurma yarıda kesildi", "err", err)
		case err != nil:
			log.Warn("skill embedding doldurulamadı (Ollama/Mongo erişilebilir mi? POST /api/skills/reindex ile tekrar dene)", "err", err)
		case rep.Embedded > 0 || rep.Failed > 0:
			log.Info("skill embedding dolduruldu", "taranan", rep.Total, "üretilen", rep.Embedded, "başarısız", rep.Failed)
		}
	}()
	return func() {
		cancel()
		wg.Wait()
	}
}
