package kiwix

import (
	"context"
	"testing"

	"github.com/kami/maven/internal/llm"
)

// Bad model output must never reach Kiwix. No model needed for this.
func TestCleanQueryRejectsJunk(t *testing.T) {
	bad := []struct{ name, raw string }{
		{"empty", ""},
		{"blank", "   \n  "},
		{"russian came back", "почему небо синее"},
		{"mixed russian", "sky синее scattering"},
		{"full sentence", "The sky looks blue because of the scattering of sunlight by air molecules"},
		{"prose with quotes", `Sure! Here is a good search query: "Rayleigh scattering", which explains it.`},
	}
	for _, c := range bad {
		if got, err := CleanQuery(c.raw); err == nil {
			t.Errorf("%s: want rejection, got %q", c.name, got)
		}
	}
}

func TestCleanQueryCleans(t *testing.T) {
	ok := []struct{ raw, want string }{
		{"Rayleigh scattering sky", "Rayleigh scattering sky"},
		{"  boiled   egg  cooking \n", "boiled egg cooking"},
		{`"virtual private network"`, "virtual private network"},
		{"solid-state drive", "solid-state drive"},
		{"cat purr.", "cat purr"},
		{"hiccup\nAlso: hiccough", "hiccup"},
		// Question words are filler to a keyword ranker, so they go.
		{"why is the sky blue", "sky blue"},
		{"how much water to drink daily", "water drink daily"},
		{"SSD vs HDD comparison", "SSD HDD comparison"},
		// Nothing but filler: keep it rather than return nothing.
		{"what is it", "what is it"},
	}
	for _, c := range ok {
		got, err := CleanQuery(c.raw)
		if err != nil {
			t.Errorf("%q: %v", c.raw, err)
			continue
		}
		if got != c.want {
			t.Errorf("%q -> %q, want %q", c.raw, got, c.want)
		}
	}
}

type fakeCompleter struct {
	out string
	req llm.Req
}

func (f *fakeCompleter) Complete(_ context.Context, r llm.Req) (string, error) {
	f.req = r
	return f.out, nil
}

func TestRewriteConstrainsTheCall(t *testing.T) {
	f := &fakeCompleter{out: `{"query":"Rayleigh scattering sky"}`}
	got, err := NewRewriter(f).Rewrite(context.Background(), "почему небо синее?")
	if err != nil {
		t.Fatalf("rewrite: %v", err)
	}
	if got != "Rayleigh scattering sky" {
		t.Errorf("query = %q", got)
	}
	if f.req.Grammar == "" {
		t.Error("no grammar sent")
	}
	if f.req.MaxTokens == 0 || f.req.MaxTokens > 32 {
		t.Errorf("max_tokens = %d, want a small cap", f.req.MaxTokens)
	}
}

func TestRewriteRejectsBadModelOutput(t *testing.T) {
	bad := []string{
		`{"query":"почему небо синее"}`, // never translated
		`{"query":""}`, // empty
		`{"query":"the sky is blue because sunlight is scattered by air"}`, // an answer
		// Note: a SHORT English prose fragment ("Let me analyze this request")
		// is under the word cap and cannot be caught here. The grammar is what
		// stops that one.
	}
	for _, out := range bad {
		f := &fakeCompleter{out: out}
		if got, err := NewRewriter(f).Rewrite(context.Background(), "почему небо синее?"); err == nil {
			t.Errorf("%s: want rejection, got %q", out, got)
		}
	}
}

// A reply that is not the JSON shape but is still usable keywords should pass.
func TestRewriteFallsBackToPlainText(t *testing.T) {
	f := &fakeCompleter{out: "Rayleigh scattering sky"}
	got, err := NewRewriter(f).Rewrite(context.Background(), "почему небо синее?")
	if err != nil || got != "Rayleigh scattering sky" {
		t.Errorf("got %q, %v", got, err)
	}
}
