package membank

import (
	"strings"
	"testing"

	"textmachine/backend/internal/lang"
	"textmachine/backend/internal/store"
)

// This probe executes the current loader, matcher and renderer. It does not
// claim that the rejected rows can reach the production render path.
func TestAuditPolysemyLoaderVersusRenderer(t *testing.T) {
	const surname = "  - src: 青山\n    sense: surname\n    dst: Циншань\n    status: approved\n"
	const landscape = "  - src: 青山\n    sense: direction\n    dst: зелёная гора\n    status: approved\n"
	const source = "青山在等。青山在远方。"

	// Both individual records are valid; refusal is specifically about their
	// coexistence, not malformed YAML or an unsupported field.
	var rows []store.GlossaryEntry
	for _, raw := range []string{surname, landscape} {
		one, err := ParseBankSeed("one-record.yaml", []byte("terms:\n"+raw))
		if err != nil || len(one.Terms) != 1 {
			t.Fatalf("a single record must load: rows=%d err=%v", len(one.Terms), err)
		}
		rows = append(rows, one.Terms...)
	}
	_, err := ParseBankSeed("both-approved.yaml", []byte("terms:\n"+surname+landscape))
	if err == nil || !strings.Contains(err.Error(), "OVERLAPPING") {
		t.Fatalf("expected specific overlapping-senses refusal, got %v", err)
	}
	t.Logf("same seed, two approved senses: REFUSED: %v", err)

	// Putting the individually valid records in different input files cannot
	// make a real run accept them: the production gather checks the joined rows.
	cols := ApprovedSharedKeyCollisions(rows)
	if len(cols) != 1 {
		t.Fatalf("joined-input collision guard must refuse exactly one pair: %v", cols)
	}
	t.Logf("two individually valid files, joined rows: REFUSED: %s", cols[0])

	// Deliberately enter BELOW the loader, as the existing render test does.
	// The real matcher and renderer preserve both signed meanings here.
	bank := Materialize(rows, false)
	sel := bank.Select(source, 1, nil, 800)
	if len(sel.Injected) != 2 {
		t.Fatalf("expected both entries to match below loader, got %d", len(sel.Injected))
	}
	block := RenderEditorConstraintBlock(sel.Injected, lang.InjectionTextsFor("ru"))
	for _, want := range []string{"青山 → «Циншань»", "青山 → «зелёная гора»"} {
		if !strings.Contains(block, want) {
			t.Fatalf("renderer dropped signed sense %q: %s", want, block)
		}
	}
	t.Logf("below loader, actual matcher+renderer: BOTH signed senses retained:\n%s", block)

	// Control: disjoint chapter windows really are supported, and never place
	// both signed meanings in the same injection.
	disjoint := "terms:\n" + surname + "    until_ch: 1\n" + landscape + "    since_ch: 2\n"
	bs, err := ParseBankSeed("disjoint-windows.yaml", []byte(disjoint))
	if err != nil {
		t.Fatalf("non-overlapping windows must load: %v", err)
	}
	bank = Materialize(bs.Terms, false)
	for _, ch := range []int{1, 2} {
		if n := len(bank.Select(source, ch, nil, 800).Injected); n != 1 {
			t.Fatalf("disjoint chapter %d must select one meaning, got %d", ch, n)
		}
	}
	t.Log("non-overlapping windows: ACCEPTED; one selected meaning in each chapter")

	// The current diagnostic suggests status:auto; with the same nonempty dst
	// this does not bypass the same-file guard (it never checks status).
	auto := strings.Replace(landscape, "status: approved", "status: auto", 1)
	_, err = ParseBankSeed("one-auto.yaml", []byte("terms:\n"+surname+auto))
	if err == nil || !strings.Contains(err.Error(), "OVERLAPPING") {
		t.Fatalf("auto with nonempty dst must still hit current same-file guard: %v", err)
	}
	t.Log("status:auto with nonempty dst in the same seed: still REFUSED")
}
