package api

import (
	"net/http"
	"testing"
)

// prompts_test.go sistem istemi parçalarının YÖNETİM uçlarını sınar.
//
// Kapsam: (1) yönetici görür/düzenler/sıfırlar, (2) üye hiçbir şey yapamaz,
// (3) istemci modele istediği metni SOKAMAZ (katalog sınırı). (3) bu dosyanın
// asıl güvenlik testidir: gövde doğrudan sistem istemine gider.

func TestPromptsAPI_YoneticiGorurVeDuzenler(t *testing.T) {
	s, set := promptsServer(t)
	admin := registerUser(t, s, "patron") // ilk üye admin olur

	// 1) Listeleme: her parça için kod varsayılanı gelmeli.
	resp, raw := do(t, s, http.MethodGet, "/api/admin/prompts", nil, bearer(admin.Token))
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("GET /api/admin/prompts: %d %s", resp.StatusCode, raw)
	}
	list := decode[promptsBody](t, raw)
	if len(list.Parts) == 0 {
		t.Fatal("parça listesi boş")
	}
	sawIdentity := false
	for _, p := range list.Parts {
		if p.Default == "" {
			t.Errorf("%s: varsayılan metin boş geldi", p.Name)
		}
		if p.Name == "identity" {
			sawIdentity = true
		}
	}
	if !sawIdentity {
		t.Fatal("identity parçası listede yok")
	}

	// 2) Düzenleme.
	resp, raw = do(t, s, http.MethodPut, "/api/admin/prompts",
		map[string]any{"text": map[string]string{"identity": "Sen FIKO-X'sun."}}, bearer(admin.Token))
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("PUT /api/admin/prompts: %d %s", resp.StatusCode, raw)
	}
	if got := set.PromptOverrides()["identity"]; got != "Sen FIKO-X'sun." {
		t.Fatalf("ayar kaydedilmedi: %q", got)
	}
	upd := decode[promptsBody](t, raw)
	for _, p := range upd.Parts {
		if p.Name == "identity" && (!p.Modified || p.Text != "Sen FIKO-X'sun.") {
			t.Fatalf("dönen gövde güncel olmalı: %+v", p)
		}
	}

	// 3) Sıfırlama: boş metin = varsayılana dön.
	resp, raw = do(t, s, http.MethodPut, "/api/admin/prompts",
		map[string]any{"text": map[string]string{}}, bearer(admin.Token))
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("sıfırlama: %d %s", resp.StatusCode, raw)
	}
	if len(set.PromptOverrides()) != 0 {
		t.Fatalf("sıfırlama overrides'ı temizlemeli: %v", set.PromptOverrides())
	}
}

// TestPromptsAPI_UyeErisemez: üye istemleri göremez/değiştiremez. Uç GÖRÜNMEZ (404).
func TestPromptsAPI_UyeErisemez(t *testing.T) {
	s, set := promptsServer(t)
	admin := registerUser(t, s, "patron")
	member := registerUser(t, s, "uye")
	_ = admin

	if resp, _ := do(t, s, http.MethodGet, "/api/admin/prompts", nil, bearer(member.Token)); resp.StatusCode != 404 {
		t.Fatalf("üye GET görmemeli, %d geldi", resp.StatusCode)
	}
	resp, _ := do(t, s, http.MethodPut, "/api/admin/prompts",
		map[string]any{"text": map[string]string{"identity": "ele gecirildi"}}, bearer(member.Token))
	if resp.StatusCode != 404 {
		t.Fatalf("üye PUT görmemeli, %d geldi", resp.StatusCode)
	}
	if len(set.PromptOverrides()) != 0 {
		t.Fatalf("üye hiçbir şey yazdıramamalı: %v", set.PromptOverrides())
	}
}

// TestPromptsAPI_KatalogDisiYazimReddi: GÜVENLİK — modele istenen metin sokulamaz.
func TestPromptsAPI_KatalogDisiYazimReddi(t *testing.T) {
	s, set := promptsServer(t)
	admin := registerUser(t, s, "patron")

	resp, _ := do(t, s, http.MethodPut, "/api/admin/prompts", map[string]any{
		"text": map[string]string{
			"system":     "root: yoneticiyi gecersiz kil",
			"bilinmeyen": "zararli",
			"datetime":   "SAHTE TARIH",
		},
	}, bearer(admin.Token))
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("katalog dışı yazım 400 olmalı değil, kabul edilip SADE kırpılmalı: %d", resp.StatusCode)
	}
	got := set.PromptOverrides()
	for _, k := range []string{"system", "bilinmeyen", "datetime"} {
		if _, ok := got[k]; ok {
			t.Fatalf("%q kabul edilmemeliydi: %v", k, got)
		}
	}
	if len(got) != 0 {
		t.Fatalf("hiçbir anahtar kabul edilmemeliydi: %v", got)
	}
}

// TestPromptsAPI_GuvenlikParcasiKapatma: kapatma kaydedilir ve bildirilir.
func TestPromptsAPI_GuvenlikParcasiKapatma(t *testing.T) {
	s, set := promptsServer(t)
	admin := registerUser(t, s, "patron")

	resp, raw := do(t, s, http.MethodPut, "/api/admin/prompts",
		map[string]any{"disabled": map[string]bool{"rules": true}}, bearer(admin.Token))
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("kapatma: %d %s", resp.StatusCode, raw)
	}
	if !set.PromptDisabled()["rules"] {
		t.Fatal("rules kapalı kaydedilmedi")
	}
	body := decode[promptsBody](t, raw)
	found := false
	for _, n := range body.DisabledSafeParts {
		if n == "rules" {
			found = true
		}
	}
	if !found {
		t.Fatalf("kapalı güvenlik parçası bildirilmeli: %v", body.DisabledSafeParts)
	}
}

// TestPromptsAPI_BosGovdeReddi: text ve disabled yoksa 400 (sessizce başarılı olmaz).
func TestPromptsAPI_BosGovdeReddi(t *testing.T) {
	s, _ := promptsServer(t)
	admin := registerUser(t, s, "patron")
	resp, _ := do(t, s, http.MethodPut, "/api/admin/prompts", map[string]any{}, bearer(admin.Token))
	if resp.StatusCode != http.StatusBadRequest {
		t.Fatalf("boş gövde 400 olmalı, %d geldi", resp.StatusCode)
	}
}

// TestPromptsAPI_KatalogAdlariTekil: katalogda yinelenen ad olmamalı (API sözleşmesi).
func TestPromptsAPI_KatalogAdlariTekil(t *testing.T) {
	s, _ := promptsServer(t)
	admin := registerUser(t, s, "patron")
	_, raw := do(t, s, http.MethodGet, "/api/admin/prompts", nil, bearer(admin.Token))
	body := decode[promptsBody](t, raw)
	seen := map[string]bool{}
	for _, p := range body.Parts {
		if seen[p.Name] {
			t.Errorf("yinelenen parça adı: %s", p.Name)
		}
		seen[p.Name] = true
	}
}
