package claim

import (
	"context"
	"fmt"
	"os"
	"strings"
	"testing"
	"time"

	"fiko-ai/internal/llm"
	"fiko-ai/internal/llm/ollama"
)

// TestE2E_GercekOllama_Okuma okuma hattını (ayırıcı + liste + vektör arama) gerçek Ollama ile dener
// ve her adımın gecikmesini raporlar. Yalnızca CLAIM_E2E_OLLAMA=1 iken çalışır.
//
//	CLAIM_E2E_OLLAMA=1 go test ./internal/claim -run TestE2E_GercekOllama_Okuma -v -timeout 20m
func TestE2E_GercekOllama_Okuma(t *testing.T) {
	if os.Getenv("CLAIM_E2E_OLLAMA") != "1" {
		t.Skip("CLAIM_E2E_OLLAMA=1 değil; gerçek Ollama denemesi atlandı")
	}
	model := e2eEnv("CLAIM_E2E_MODEL", "gemma4:latest")
	embed := e2eEnv("CLAIM_E2E_EMBED", "qwen3-embedding")
	base := e2eEnv("OLLAMA_BASE_URL", "http://localhost:11434")

	prov := &countingLLM{Provider: ollama.New(base, model, 5*time.Minute).WithEmbedModel(embed)}
	embedder := prov.Provider.(llm.Embedder)
	repo, audit := NewMemoryRepo(), NewMemoryAuditRepo()
	svc := NewService(repo, audit, prov, embedder, Config{Model: model, EmbedModel: embed}, nil)
	defer svc.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
	defer cancel()
	actor := Actor{ID: "usr_fikri", Name: "Fikri", Role: RolePatron}

	t0 := time.Now()
	if _, err := svc.Write(ctx, actor, "Müşterilerimiz: ACME Kalıp A.Ş. (tel 0224 111 22 33), Barış Metal Ltd. (tel 0224 444 55 66) "+
		"ve Çelik Boya San. (tel 0224 777 88 99). Barış Metal'in yetkilisi Ahmet Bey."); err != nil {
		t.Fatalf("tohum yazma: %v", err)
	}
	firms, _ := repo.Count(ctx, Filter{Kinds: []string{KindFirma}})
	t.Logf("tohum yazma %s sürdü; firma=%d", time.Since(t0).Round(time.Second), firms)
	if firms != 3 {
		t.Fatalf("tohumda 3 firma beklenirdi, var: %d", firms)
	}

	rd := NewReader(repo, prov, embedder, ReadConfig{Model: model, EmbedModel: embed})

	cases := []struct {
		msg      string
		wantList bool
		check    func(t *testing.T, p *Prepared)
	}{
		{"firmaların listesini ver", true, func(t *testing.T, p *Prepared) {
			if p.List == nil || p.List.Total != 3 || strings.Count(p.Append, "\n1. ")+strings.Count(p.Append, "1. ") < 1 ||
				!strings.Contains(p.Append, "Toplam: 3 firma") {
				t.Errorf("liste eksik/yanlış: %+v", p.List)
			}
		}},
		{"Barış Metal'in telefonu kaç?", false, func(t *testing.T, p *Prepared) {
			if len(p.Hits) == 0 || !strings.Contains(p.Hits[0].Claim.Text, "Barış") {
				t.Errorf("ilk isabet Barış Metal olmalıydı: %+v", p.Hits)
			}
		}},
		{"Merhaba, nasılsın?", false, func(t *testing.T, p *Prepared) {}},
		{"Bütün müşterilerimizi tek tek say", true, func(t *testing.T, p *Prepared) {
			if p.List == nil || p.List.Kind != KindFirma {
				t.Errorf("müşteriler firma listesi sayılmalıydı: %+v", p.List)
			}
		}},
	}
	for _, c := range cases {
		start := time.Now()
		p, err := rd.Prepare(ctx, c.msg, actor)
		if err != nil {
			t.Errorf("%q: Prepare hata: %v", c.msg, err)
			continue
		}
		hit := ""
		if len(p.Hits) > 0 {
			hit = fmt.Sprintf("[skor %.3f] %s", p.Hits[0].Score, p.Hits[0].Claim.Text)
			for _, h := range p.Hits[1:] {
				hit += fmt.Sprintf(" | %.3f", h.Score)
			}
		}
		t.Logf("%q → niyet=%s kind=%q isabet=%d degraded=%v süre=%s ilk=%q",
			c.msg, p.Intent.Type, p.Intent.Kind, len(p.Hits), p.Degraded, time.Since(start).Round(time.Millisecond), hit)
		if (p.Intent.Type == IntentList) != c.wantList {
			t.Errorf("%q: liste=%v beklenen %v", c.msg, p.Intent.Type == IntentList, c.wantList)
		}
		c.check(t, p)
	}
}
