package scrabble

import (
	"testing"

	"github.com/iliadenisov/alphabet"
	dawg "github.com/iliadenisov/dafsa"

	"gitea.iliadenisov.ru/developer/scrabble-solver/dictdawg"
	"gitea.iliadenisov.ru/developer/scrabble-solver/wordlist"
)

func bruteCrossSet(words [][]byte, above, below []byte, size int) letterSet {
	set := make(map[string]bool, len(words))
	for _, w := range words {
		set[string(w)] = true
	}
	var out letterSet
	for x := range size {
		w := make([]byte, 0, len(above)+1+len(below))
		w = append(w, above...)
		w = append(w, byte(x))
		w = append(w, below...)
		if set[string(w)] {
			out |= letterSet(1) << uint(x)
		}
	}
	return out
}

func TestDAWGCrossSetMatchesBruteForce(t *testing.T) {
	const size = 26
	words := wordlist.Encode(
		[]string{"cat", "cot", "cut", "cap", "cab", "at", "it"},
		alphabet.Latin(), 2, 15)

	finder, err := dictdawg.Build(alphabet.Latin(), words)
	if err != nil {
		t.Fatal(err)
	}
	cur, err := dawg.NewCursor(finder)
	if err != nil {
		t.Fatal(err)
	}

	cases := []struct {
		name         string
		above, below []byte
	}{
		{"c_t", []byte{2}, []byte{19}}, // expect {a,o,u}
		{"_t", nil, []byte{19}},        // expect {a,i}
		{"c_", []byte{2}, nil},         // expect {} (no two-letter c-words)
		{"a_t", []byte{0}, []byte{19}}, // expect {}
	}
	for _, tc := range cases {
		want := bruteCrossSet(words, tc.above, tc.below, size)
		if got := dawgCrossSet(cur, tc.above, tc.below, size); got != want {
			t.Errorf("%s: dawgCrossSet = %026b, want %026b", tc.name, got, want)
		}
	}

	// c_t must be exactly {a(0), o(14), u(20)}.
	want := letterSet(0)
	for _, x := range []byte{0, 14, 20} {
		want |= letterSet(1) << x
	}
	if got := dawgCrossSet(cur, []byte{2}, []byte{19}, size); got != want {
		t.Errorf("c_t cross-set = %026b, want {a,o,u} = %026b", got, want)
	}

	// No perpendicular neighbours: every letter is allowed.
	if got := dawgCrossSet(cur, nil, nil, size); got != fullSet(size) {
		t.Errorf("empty context = %026b, want full", got)
	}
}
