package lexicon

import "testing"

func TestLookupKnownWord(t *testing.T) {
	l := New()
	res, err := l.Lookup("happy")
	if err != nil {
		t.Fatalf("Lookup: %v", err)
	}
	if len(res.Definitions) == 0 {
		t.Errorf("expected definitions for %q, got none", "happy")
	}
	if len(res.Synonyms) == 0 {
		t.Errorf("expected synonyms for %q, got none", "happy")
	}
	if len(res.Synonyms) > maxSynonyms {
		t.Errorf("synonyms not capped: got %d, want <= %d", len(res.Synonyms), maxSynonyms)
	}
	if len(res.Definitions) > maxDefinitions {
		t.Errorf("definitions not capped: got %d, want <= %d", len(res.Definitions), maxDefinitions)
	}
}

func TestLookupMorphology(t *testing.T) {
	l := New()
	// Inflected forms should resolve to their base entry via candidates().
	for _, w := range []string{"running", "studies", "boxes", "quickly", "stopped"} {
		res, err := l.Lookup(w)
		if err != nil {
			t.Fatalf("Lookup(%q): %v", w, err)
		}
		if len(res.Definitions) == 0 && len(res.Synonyms) == 0 {
			t.Errorf("expected some result for inflected %q, got nothing", w)
		}
	}
}

func TestLookupUnknownWord(t *testing.T) {
	l := New()
	res, err := l.Lookup("zzzxqqq")
	if err != nil {
		t.Fatalf("Lookup: %v", err)
	}
	if len(res.Definitions) != 0 || len(res.Synonyms) != 0 {
		t.Errorf("expected empty result for nonsense word, got %+v", res)
	}
	// Empty result must still serialize as [] not null for the frontend.
	if res.Definitions == nil || res.Synonyms == nil {
		t.Errorf("empty slices must be non-nil for JSON []: %+v", res)
	}
}

func TestGloss(t *testing.T) {
	l := New()
	// A common word carries a Chinese gloss...
	res, err := l.Gloss("river")
	if err != nil {
		t.Fatalf("Gloss: %v", err)
	}
	if res.Word != "river" {
		t.Errorf("Word = %q, want %q", res.Word, "river")
	}
	if res.Gloss == "" {
		t.Errorf("expected a Chinese gloss for %q, got none", "river")
	}
	// ...and the inflected form resolves via the same de-inflection.
	inflected, err := l.Gloss("rivers")
	if err != nil {
		t.Fatalf("Gloss(rivers): %v", err)
	}
	if inflected.Gloss == "" {
		t.Errorf("expected a gloss for inflected %q, got none", "rivers")
	}
	// A nonsense word is a clean empty (not an error).
	miss, err := l.Gloss("zzzxqqq")
	if err != nil {
		t.Fatalf("Gloss(miss): %v", err)
	}
	if miss.Gloss != "" {
		t.Errorf("expected empty gloss for nonsense word, got %q", miss.Gloss)
	}
}

func TestLookupIncludesGloss(t *testing.T) {
	l := New()
	res, err := l.Lookup("happy")
	if err != nil {
		t.Fatalf("Lookup: %v", err)
	}
	if res.Gloss == "" {
		t.Errorf("expected Lookup to include a Chinese gloss for %q", "happy")
	}
}

func TestCandidates(t *testing.T) {
	cases := map[string]string{
		"cats":    "cat",
		"studies": "study",
		"running": "run",
		"hoped":   "hope",
		"quickly": "quick",
		"happily": "happy",
	}
	for word, want := range cases {
		got := candidates(word)
		found := false
		for _, c := range got {
			if c == want {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("candidates(%q) = %v, missing expected base %q", word, got, want)
		}
	}
}
