package builtin

import (
	"testing"
)

// ---- Onay formu: yazma/silme kullanıcı onayı olmadan ÇALIŞMAZ ----

// EN KRİTİK KURAL: model confirmed:true deyimini kendisi gönderebilirdi. Bu yüzden
// tool, onay alınmadan asla yazmaz/silmez. Canlı hata (04.10.2026): model geri alınamaz
// işlemleri kendi başına başlatabiliyordu.
func TestBizAdd_WithoutConfirmReturnsFormNotRecord(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	out := mustRun(t, defs, "biz.add", map[string]any{
		"collection": "customers",
		"data":       map[string]any{"name": "Onaysız Müşteri"},
	})
	if out["ok"] != false || out["pending"] != true {
		t.Fatalf("onay bekleniyordu, kayıt yazıldı: %+v", out)
	}
	if out["record"] != nil {
		t.Errorf("onaysız kayıt dönmemeli: %+v", out["record"])
	}
	cf, _ := out["confirm"].(ConfirmForm)
	if cf.Title == "" || cf.ConfirmLabel != "Kaydet" {
		t.Errorf("onay formu eksik: %+v", cf)
	}
	// Konuşmadan gelen alan forma DOLDURULMALI (kullanıcı ne yazılacağını görmeli).
	if v := fieldValue(cf.Fields, "name"); v != "Onaysız Müşteri" {
		t.Errorf("forma aktarılan alan = %q, beklenen konuşmadaki değer", v)
	}
}

func TestBizDelete_WithoutConfirmReturnsFormAndKeepsRecord(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	added := mustRunConfirmed(t, defs, "biz.add", map[string]any{
		"collection": "customers", "data": map[string]any{"name": "Silinecek"},
	})
	ref := added["record"].(map[string]any)["id"].(string)

	out := mustRun(t, defs, "biz.delete", map[string]any{"collection": "customers", "ref": ref})
	if out["ok"] != false || out["pending"] != true {
		t.Fatalf("silme onay beklemeliydi: %+v", out)
	}
	cf, _ := out["confirm"].(ConfirmForm)
	if !cf.Destructive {
		t.Error("silme formu destructive olmalı")
	}
	if cf.ConfirmLabel != "Sil" {
		t.Errorf("buton metni = %q", cf.ConfirmLabel)
	}
	// Kayıt GERÇEKTEN durmalı: onaysız silinmemeli.
	found := mustRun(t, defs, "biz.find", map[string]any{"collection": "customers"})
	if found["total"].(int) != 1 {
		t.Fatalf("onaysız silme kaydı kaybetti: %+v", found)
	}
}

// Onay geldikten sonra işlem GERÇEKTEN çalışır.
func TestBizDelete_WithConfirmActuallyDeletes(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	added := mustRunConfirmed(t, defs, "biz.add", map[string]any{
		"collection": "customers", "data": map[string]any{"name": "Gidecek"},
	})
	ref := added["record"].(map[string]any)["id"].(string)

	out := mustRunConfirmed(t, defs, "biz.delete", map[string]any{"collection": "customers", "ref": ref})
	if out["deleted"] != true {
		t.Fatalf("onaylı silme çalışmadı: %+v", out)
	}
	found := mustRun(t, defs, "biz.find", map[string]any{"collection": "customers"})
	if found["total"].(int) != 0 {
		t.Fatalf("kayıt silinmedi: %+v", found)
	}
}

// Silinecek kayıt YOKSA form üretilmemeli: kullanıcıya "onayla" denip sonra hata
// göstermek kötü kullanım olurdu; kayıt çözülemezse anlaşılır hata verilir.
func TestBizDelete_UnknownRefFailsWithoutForm(t *testing.T) {
	defs, err := bizDefinitions(testOptions(t))
	if err != nil {
		t.Fatal(err)
	}
	if _, err = runDef(t, defs, "biz.delete", map[string]any{
		"collection": "customers", "ref": "olmayan-kayit",
	}); err == nil {
		t.Fatal("olmayan kayıt için hata bekleniyordu")
	}
}

// ---- Politika ----

func TestNeedsConfirm_PolicyTable(t *testing.T) {
	cases := []struct {
		mode    string
		risky   bool
		missing int
		want    bool
	}{
		{ConfirmNever, true, 3, false},    // hiçbir zaman
		{ConfirmNever, false, 0, false},   // hiçbir zaman
		{ConfirmAlways, false, 0, true},   // her şey
		{ConfirmAlways, true, 0, true},    //
		{ConfirmRisky, true, 0, true},     // sadece geri alınamaz
		{ConfirmRisky, false, 0, false},   //
		{ConfirmRisky, false, 2, false},   // eksik olsa bile "risky" modu sormaz
		{ConfirmMissing, false, 0, false}, // eksik yoksa sormaz
		{ConfirmMissing, false, 1, true},  // eksik varsa sorar
		{ConfirmMissing, true, 0, false},  //
		{"bilinmeyen", true, 0, true},     // geçersiz mod → güvenli varsayılan (risky)
	}
	for _, tc := range cases {
		if got := needsConfirm(tc.mode, "x", tc.risky, tc.missing); got != tc.want {
			t.Errorf("needsConfirm(%q, risky=%v, missing=%d) = %v, beklenen %v",
				tc.mode, tc.risky, tc.missing, got, tc.want)
		}
	}
}

// ---- form alanları ----

func TestAddConfirmFields_FillsFromConversation(t *testing.T) {
	sp, ok := specFor("customers")
	if !ok {
		t.Fatal("customers şeması yok")
	}
	// Konuşmadan yalnızca ad geldi; diğer alanlar gelmedi.
	fields := addConfirmFields(sp, map[string]any{"name": "Aril"}, "2026-03-10")

	if fieldValue(fields, "name") != "Aril" {
		t.Error("konuşmadaki alan forma aktarılmadı")
	}
	// Enum alanı seçim kutusu olmalı ve geçerli değerler listelenmeli.
	status := fieldByKey(fields, "status")
	if status == nil || status.Type != "enum" || len(status.Options) == 0 {
		t.Fatalf("status enum olmalı: %+v", status)
	}
	// Varsayılan değer forma yazılır: kullanıcı ne kaydedileceğini görsün.
	if status.Value != "active" {
		t.Errorf("enum varsayılanı forma yazılmadı: %q", status.Value)
	}
}

func TestSortFields_MissingRequiredFirst(t *testing.T) {
	fields := []ConfirmField{
		{Key: "notlar", Type: "text", Editable: true},
		{Key: "id", Type: "text", Editable: false},
		{Key: "tutar", Type: "number"},
		{Key: "baslik", Required: true, Missing: true},
		{Key: "durum", Type: "enum"},
	}
	got := sortFields(fields)
	if got[0].Key != "baslik" {
		t.Errorf("eksik zorunlu alan en başta olmalı, ilk = %q", got[0].Key)
	}
	if got[len(got)-1].Key != "id" {
		t.Errorf("değiştirilemez alan en sonda olmalı, son = %q", got[len(got)-1].Key)
	}
}

func TestDeleteConfirmFields_ReadOnly(t *testing.T) {
	sp, _ := specFor("customers")
	rec := map[string]any{"id": "cus_1", "name": "Aril", "status": "active", "notes": "not"}
	fields := deleteConfirmFields(sp, rec, "cus_1")
	for _, f := range fields {
		if f.Editable {
			t.Errorf("silme formunda %q alanı düzenlenebilir olmamalı", f.Key)
		}
	}
	if fieldValue(fields, "name") != "Aril" {
		t.Error("kayıt alanları forma taşınmalı: kullanıcı ne silindiğini görmeli")
	}
}

// ---- yardımcılar ----

func fieldByKey(fields []ConfirmField, key string) *ConfirmField {
	for i := range fields {
		if fields[i].Key == key {
			return &fields[i]
		}
	}
	return nil
}

func fieldValue(fields []ConfirmField, key string) string {
	if f := fieldByKey(fields, key); f != nil {
		return f.Value
	}
	return ""
}
