package claim

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"testing"

	"fiko-ai/internal/llm"
)

// Faz 7 — uçtan uca: 140 firma yaz → listele (sayı tutuyor mu) → iki kullanıcıdan çelişkili bilgi →
// üye karar veremez, patron netleştirir → silme yetkisi → denetim izi. Parçalar ayrı ayrı testlidir;
// bu test aralarındaki ZİNCİRİ (aynı depo, aynı servis) doğrular. LLM/embedding sahtedir.

var faz7Patron = Actor{ID: "u_patron", Name: "Fikri", Role: RolePatron}

func TestFaz7_140Firma_Celiski_Silme_Denetim(t *testing.T) {
	ctx := context.Background()
	var lines []string
	for i := 0; i < 140; i++ {
		lines = append(lines, fmt.Sprintf("Firma %03d Kalıp A.Ş.", i))
	}
	prov := &fakeLLM{fn: firmEcho}
	dec := &fakeDecider{verdict: VerdictConflict}
	s, repo, aud := newSvc(t, prov, &fakeEmb{}, dec)
	rd := NewReader(repo, nil, nil, ReadConfig{Model: "m", EmbedModel: "emb", TopK: 3, PageSize: 50})

	// 1) Ali 140 firmayı tek mesajda girer; liste sunucuda üretilir ve sayı tutar.
	res := mustWrite(t, s, ali, strings.Join(lines, "\n"))
	if res.Added != 140 || len(res.Conflicts) != 0 {
		t.Fatalf("140 kayıt, 0 çelişki beklenirdi: %+v", res)
	}
	ls, err := rd.List(ctx, KindFirma, faz7Patron)
	if err != nil || ls.Total != 140 || ls.Conflicts != 0 || len(ls.Items) != 140 {
		t.Fatalf("liste 140 olmalı: %+v %v", ls, err)
	}
	if !strings.HasSuffix(ls.Text, "Toplam: 140 firma") || !strings.Contains(ls.Text, "140. Firma 139") {
		t.Fatalf("liste metni eksik/yanlış sayılı: ...%s", ls.Text[max(0, len(ls.Text)-120):])
	}

	// 2) Veli aynı firma için FARKLI bilgi girer → ikisi de çelişkili, eski kayıt silinmez.
	conflicting := []Candidate{{Text: "Firma 007 Kalıp A.Ş. artık tedarikçidir.", Kind: KindFirma, Key: "Firma 007 Kalıp A.Ş."}}
	b, _ := json.Marshal(map[string]any{"remember": conflicting})
	prov.fn = func(int, llm.Request) (llm.Result, error) { return llm.Result{Content: string(b)}, nil }
	res = mustWrite(t, s, veli, "Firma 007 artık tedarikçi.")
	if res.Added != 1 || len(res.Conflicts) != 1 || dec.calls != 1 {
		t.Fatalf("1 çelişki beklenirdi: %+v kararlar=%d", res, dec.calls)
	}
	msg := res.Message()
	if !strings.Contains(msg, "1 çelişki var") || !strings.Contains(msg, "patron karar verecek") ||
		strings.Contains(msg, "Ali") || strings.Contains(msg, "Veli") {
		t.Fatalf("özet nötr olmalı ve kimseyi anmamalı: %q", msg)
	}
	ls, _ = rd.List(ctx, KindFirma, faz7Patron)
	if ls.Total != 141 || ls.Conflicts != 2 || strings.Count(ls.Text, "[çelişkili]") != 2 ||
		!strings.Contains(ls.Text, "patron belirler") {
		t.Fatalf("liste: 141 kayıt, 2 çelişkili işaret beklenirdi: total=%d conflicts=%d", ls.Total, ls.Conflicts)
	}

	// 3) Üye çelişkileri görür ama karar veremez; kaydın sahibi Ali bile.
	gs, err := s.Conflicts(ctx, veli)
	if err != nil || len(gs) != 1 || len(gs[0].Claims) != 2 || gs[0].Key != "firma 007 kalip a s" {
		t.Fatalf("tek çelişki kümesi beklenirdi: %+v %v", gs, err)
	}
	var aliClaim, veliClaim Claim
	for _, c := range gs[0].Claims {
		if c.AuthorID == ali.ID {
			aliClaim = c
		} else {
			veliClaim = c
		}
	}
	if aliClaim.ID == "" || veliClaim.ID == "" || veliClaim.ConflictsWith != aliClaim.ID {
		t.Fatalf("iki yazar ve ConflictsWith bağı beklenirdi: %+v", gs[0].Claims)
	}
	for _, who := range []Actor{ali, veli} {
		if _, err := s.Resolve(ctx, who, aliClaim.ID, DecisionKeep); !errors.Is(err, ErrPatronOnly) {
			t.Fatalf("%s karar veremez: %v", who.Name, err)
		}
	}

	// 4) Patron Ali'nin bilgisini geçerli sayar: Veli'ninki geçersiz olur, listede 140'a döner.
	if _, err := s.Resolve(ctx, faz7Patron, aliClaim.ID, DecisionKeep); err != nil {
		t.Fatal(err)
	}
	ls, _ = rd.List(ctx, KindFirma, faz7Patron)
	if ls.Total != 140 || ls.Conflicts != 0 || strings.Contains(ls.Text, "tedarikçidir") {
		t.Fatalf("karar sonrası 140, çelişkisiz, geçersiz bilgi görünmez: total=%d conflicts=%d", ls.Total, ls.Conflicts)
	}
	if got, _ := repo.Get(ctx, veliClaim.ID); got == nil || got.Status != StatusInvalid {
		t.Fatalf("geçersiz kayıt silinmemeli, durumu gecersiz olmalı: %+v", got)
	}
	// Denetim izi (yeni önce): Ali'nin kaydı create → (Veli) celiskili → (patron) aktif.
	es, _ := aud.ListByClaim(ctx, aliClaim.ID, 0, 0)
	if len(es) != 3 || es[0].By != faz7Patron.ID || es[1].By != veli.ID || es[2].By != ali.ID ||
		es[0].After.Status != StatusActive || es[1].After.Status != StatusConflict || es[2].Action != ActionCreate {
		t.Fatalf("Ali'nin kaydı için 3 girdilik iz beklenirdi: %+v", es)
	}

	// 5) Silme: yazar ya da patron. Başka üye silemez; silinen değer denetimde yaşar.
	victim := byKey(t, repo, KindFirma, NormalizeKey("Firma 010 Kalıp A.Ş."))[0]
	if err := s.Delete(ctx, veli, victim.ID); !errors.Is(err, ErrForbidden) {
		t.Fatalf("başkasının kaydını silemez: %v", err)
	}
	if err := s.Delete(ctx, ali, victim.ID); err != nil {
		t.Fatal(err)
	}
	other := byKey(t, repo, KindFirma, NormalizeKey("Firma 020 Kalıp A.Ş."))[0]
	if err := s.Delete(ctx, faz7Patron, other.ID); err != nil {
		t.Fatal(err)
	}
	ls, _ = rd.List(ctx, KindFirma, faz7Patron)
	if ls.Total != 138 || !strings.HasSuffix(ls.Text, "Toplam: 138 firma") {
		t.Fatalf("iki silme sonrası 138 beklenirdi: %d", ls.Total)
	}
	hist, err := s.History(ctx, faz7Patron, victim.ID, 0, 0)
	if err != nil || len(hist) != 2 || hist[0].Action != ActionDelete || hist[0].By != ali.ID ||
		hist[0].Before == nil || hist[0].Before.Text != victim.Text {
		t.Fatalf("silinen değer denetimde kalmalı: %+v %v", hist, err)
	}
	if _, err := s.History(ctx, veli, victim.ID, 0, 0); !errors.Is(err, ErrForbidden) {
		t.Fatalf("geçmişi yalnızca yazar/patron görür: %v", err)
	}
}
