package builtin

import (
	"strings"
	"testing"
)

// CANLI HATA — model halüsinasyonu: kullanıcı "hangi projeler var, sınıf çıkarır mısın?"
// dediğinde model, HİÇ KAYDI OLMAYAN koleksiyonlardan (tasks, invoices, expenses, products,
// notes) varmış gibi liste uydurdu. Sebep: summary boş koleksiyonları sessizce 0'a
// düşürüyordu; model hangi koleksiyonda veri olduğunu BİLEMEYDİĞİ için tahmin yürüttü.
//
// Çözüm: summary GERÇEK envanteri verir. Test bunu kilitler.
func TestSummary_RevealsRealCollectionInventory(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	// Yalnızca customers ve employees'e kayıt var; diğerleri BOŞ.
	mustRunConfirmed(t, defs, "biz.add", map[string]any{
		"collection": "customers", "data": map[string]any{"name": "Otimsa"},
	})
	mustRunConfirmed(t, defs, "biz.add", map[string]any{
		"collection": "employees", "data": map[string]any{"name": "Fikri"},
	})

	out := mustRun(t, defs, "biz.summary", map[string]any{})

	// 1) Her koleksiyon envanterde bulunmalı (sayım 0 dahil) — model neyin var
	//    olduğunu, neyin olmadığını görebilmeli.
	inv, ok := out["collections"].([]any)
	if !ok || len(inv) == 0 {
		t.Fatalf("collections envanteri yok: %+v", out["collections"])
	}
	if len(inv) != len(bizSpecs) {
		t.Fatalf("envanterde %d koleksiyon var, beklenen %d", len(inv), len(bizSpecs))
	}
	counts := map[string]int{}
	for _, it := range inv {
		m := it.(map[string]any)
		if m["collection"] == nil || m["count"] == nil {
			t.Fatalf("eksik envanter satırı: %+v", m)
		}
		counts[m["collection"].(string)] = int(m["count"].(int))
	}
	for _, empty := range []string{"tasks", "invoices", "expenses", "products", "notes"} {
		if _, seen := counts[empty]; !seen {
			t.Errorf("envanterde %s yok (model bunu uydurur)", empty)
		}
		if counts[empty] != 0 {
			t.Errorf("%s sayısı = %d, beklenen 0", empty, counts[empty])
		}
	}
	if counts["customers"] != 1 || counts["employees"] != 1 {
		t.Errorf("dolu koleksiyon sayımları yanlış: %+v", counts)
	}

	// 2) nonEmptyCollections YALNIZCA gerçekten kayıt olanları listelemeli.
	//    Bu, modelin uydurmasını engelleyen asıl alan (canlı hatanın kaynağı).
	ne, ok := out["nonEmptyCollections"].([]string)
	if !ok {
		t.Fatalf("nonEmptyCollections []string olmalı: %T", out["nonEmptyCollections"])
	}
	for _, name := range ne {
		if counts[name] == 0 {
			t.Errorf("nonEmptyCollections boş koleksiyonu içeriyor: %s", name)
		}
	}
	if len(ne) != 2 {
		t.Errorf("nonEmptyCollections = %v, beklenen 2 kayıtlı koleksiyon", ne)
	}
}

// Hiç kayıt yokken model "veri varmış" izlenimi edinmemeli; açık uyarı verilmelidir.
func TestSummary_EmptyStoreWarnsAgainstFabrication(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	out := mustRun(t, defs, "biz.summary", map[string]any{})

	ne, ok := out["nonEmptyCollections"].([]string)
	if !ok || len(ne) != 0 {
		t.Fatalf("nonEmptyCollections boş olmalı: %v", out["nonEmptyCollections"])
	}
	note, _ := out["note"].(string)
	if !strings.Contains(note, "kayıt yok") {
		t.Errorf("boş depo uyarısı yok, note = %q", note)
	}
}

// biz.find boş döndüğünde model NEDEN boş olduğunu bilmelidir: koleksiyon tamamen mi
// boş, yoksa arama mı tutmadı? Bu ayrım yapılmazsa model veri uydurur.
func TestFind_EmptyCollectionExplainsWhy(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}

	// (a) Koleksiyon hiç boş değil, ama arama tutmamış.
	mustRunConfirmed(t, defs, "biz.add", map[string]any{
		"collection": "customers", "data": map[string]any{"name": "Otimsa"},
	})
	out := mustRun(t, defs, "biz.find", map[string]any{
		"collection": "customers", "query": "boyle-bir-kayit-yok",
	})
	if out["empty"] != true {
		t.Fatalf("empty işareti yok: %+v", out)
	}
	if out["collectionTotal"] != 1 {
		t.Errorf("collectionTotal = %v, beklenen 1", out["collectionTotal"])
	}
	note, _ := out["note"].(string)
	if !strings.Contains(note, "eşleşmedi") {
		t.Errorf("arama tutmadı açıklaması yok: %q", note)
	}
	if strings.Contains(note, "HİÇ KAYIT YOK") {
		t.Errorf("koleksiyon boş değilken 'HİÇ KAYIT YOK' denmemeli: %q", note)
	}

	// (b) Koleksiyonun tamamı boş: farklı (ve daha güçlü) açıklama beklenir.
	out2 := mustRun(t, defs, "biz.find", map[string]any{"collection": "invoices"})
	note2, _ := out2["note"].(string)
	if !strings.Contains(note2, "HİÇ KAYIT YOK") {
		t.Errorf("boş koleksiyon açıklaması yok: %q", note2)
	}
	if out2["collectionTotal"] != 0 {
		t.Errorf("collectionTotal = %v, beklenen 0", out2["collectionTotal"])
	}
}

// Kayıt bulunduğunda ek açıklama EKLENMEMELİ: mevcut çıktı sözleşmesi bozulmaz.
func TestFind_NonEmptyUnchangedContract(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	mustRunConfirmed(t, defs, "biz.add", map[string]any{
		"collection": "customers", "data": map[string]any{"name": "Otimsa"},
	})
	out := mustRun(t, defs, "biz.find", map[string]any{"collection": "customers"})
	if _, exists := out["empty"]; exists {
		t.Errorf("dolu sonuçta 'empty' alanı olmamalı: %+v", out)
	}
	if _, exists := out["note"]; exists {
		t.Errorf("dolu sonuçta 'note' alanı olmamalı: %+v", out)
	}
	if out["count"] != 1 || out["total"] != 1 {
		t.Errorf("count/total bozuldu: %+v", out)
	}
}

// Tool AÇIKLAMASI modele ne yapmaması gerektiğini söylemeli (yalnızca çıktı alanına
// güvenmek yeterli değil: model büyük özetlerde envanteri atlayabiliyor).
func TestSummaryDescriptionTellsModelNotToFabricate(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	var desc string
	for _, d := range defs {
		if d.Tool.Name == "biz.summary" {
			desc = d.Tool.Description
		}
	}
	for _, want := range []string{"collections", "nonEmptyCollections", "uydurma"} {
		if !strings.Contains(desc, want) {
			t.Errorf("biz.summary açıklaması %q bilgisini içermiyor:\n%s", want, desc)
		}
	}
}
