package claim

import (
	"errors"
	"strings"
	"testing"
	"time"
)

func TestMemoryRepo_Contract(t *testing.T) {
	RepositoryContract(t, func() Repository { return NewMemoryRepo() })
}

func TestMemoryAuditRepo_Contract(t *testing.T) {
	AuditRepositoryContract(t, func() AuditRepository { return NewMemoryAuditRepo() })
}

func TestNormalizeKey(t *testing.T) {
	cases := map[string]string{
		"Acme Kalıp":          "acme kalip",
		"ACME   KALIP":        "acme kalip",
		"  Çelik-Tezgâh A.Ş.": "celik tezgah a s",
		"İSTANBUL Ltd.":       "istanbul ltd",
		"Işık  Makine":        "isik makine",
		"B-12":                "b 12",
		"":                    "",
		"...":                 "",
	}
	for in, want := range cases {
		if got := NormalizeKey(in); got != want {
			t.Errorf("NormalizeKey(%q) = %q, beklenen %q", in, got, want)
		}
	}
	// Aynı varlığın yazım farkları aynı anahtarı vermeli; farklı adlar vermemeli.
	if NormalizeKey("Acme Kalıp A.Ş.") != NormalizeKey("acme  kalip a.s") {
		t.Error("yazım farkı aynı anahtarı vermeli")
	}
	if NormalizeKey("Acme Kalıp") == NormalizeKey("Acme Kalıp 2") {
		t.Error("benzer ama farklı adlar AYRI anahtar olmalı (listelik türde otomatik birleşme yok)")
	}
	// Normalleştirme idempotenttir (Validate bunu şart koşar).
	for in := range cases {
		k := NormalizeKey(in)
		if NormalizeKey(k) != k {
			t.Errorf("NormalizeKey idempotent değil: %q → %q → %q", in, k, NormalizeKey(k))
		}
	}
}

func validClaim() *Claim {
	now := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC)
	return &Claim{ID: "c1", Text: "Acme bir müşteridir", Kind: KindFirma, Key: "acme", AuthorID: "u1",
		AuthorName: "Fikri", CreatedAt: now, UpdatedAt: now, Status: StatusActive}
}

func TestClaimValidate(t *testing.T) {
	if err := validClaim().Validate(); err != nil {
		t.Fatalf("geçerli kayıt reddedildi: %v", err)
	}
	// Listelik olmayan türde anahtar zorunlu değil.
	g := validClaim()
	g.Kind, g.Key = KindGeneral, ""
	if err := g.Validate(); err != nil {
		t.Errorf("anahtarsız genel kayıt geçerli olmalı: %v", err)
	}

	bad := map[string]func(c *Claim){
		"id":         func(c *Claim) { c.ID = "" },
		"text":       func(c *Claim) { c.Text = "   " },
		"text-uzun":  func(c *Claim) { c.Text = strings.Repeat("ş", MaxTextRunes+1) },
		"kind":       func(c *Claim) { c.Kind = "Firma" },
		"kind-bos":   func(c *Claim) { c.Kind = "" },
		"kind-sayi":  func(c *Claim) { c.Kind = "1firma" },
		"key-liste":  func(c *Claim) { c.Key = "" }, // firma → anahtar zorunlu
		"key-norm":   func(c *Claim) { c.Key = "Acme Kalıp" },
		"key-uzun":   func(c *Claim) { c.Key = strings.Repeat("a", MaxKeyRunes+1) },
		"author":     func(c *Claim) { c.AuthorID = "" },
		"status":     func(c *Claim) { c.Status = "bilinmez" },
		"kendi-yeri": func(c *Claim) { c.Supersedes = c.ID },
	}
	for name, mutate := range bad {
		c := validClaim()
		mutate(c)
		err := c.Validate()
		var ve *ValidationError
		if !errors.As(err, &ve) || len(ve.Errors) == 0 {
			t.Errorf("%s: ValidationError beklenirdi: %v", name, err)
		}
	}
	// Birden çok hata tek seferde raporlanır.
	c := validClaim()
	c.ID, c.AuthorID, c.Status = "", "", ""
	var ve *ValidationError
	if err := c.Validate(); !errors.As(err, &ve) || len(ve.Errors) != 3 {
		t.Errorf("3 alan hatası beklenirdi: %v", err)
	}
}

func TestClaimSnapshotDropsVector(t *testing.T) {
	c := validClaim()
	c.Embedding, c.EmbedModel = []float32{1, 2}, "m"
	s := c.Snapshot()
	if len(s.Embedding) != 0 || s.EmbedModel != "" || s.Text != c.Text {
		t.Errorf("snapshot vektörsüz ve diğer alanlar tam olmalı: %+v", s)
	}
	if len(c.Embedding) != 2 {
		t.Error("snapshot orijinali değiştirmemeli")
	}
}

func TestIsListKind(t *testing.T) {
	for _, k := range []string{KindFirma, KindKisi, KindUrun} {
		if !IsListKind(k) {
			t.Errorf("%s listelik olmalı", k)
		}
	}
	for _, k := range []string{KindGorev, KindGeneral, "pdks", ""} {
		if IsListKind(k) {
			t.Errorf("%q listelik olmamalı", k)
		}
	}
}
