package engine

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"testing"

	"gitea.iliadenisov.ru/developer/scrabble-solver/rules"
	"gitea.iliadenisov.ru/developer/scrabble-solver/scrabble"
)

// testVersion labels the single dictionary version the tests register.
const testVersion = "test"

// testReg is the shared registry of all three variants, hydrated once by
// TestMain and reused by the read-only tests.
var testReg *Registry

// TestMain loads the committed dictionaries once and shares them with every
// test. It fails loudly when the dictionary directory is absent (per
// docs/TESTING.md) rather than skipping coverage.
func TestMain(m *testing.M) {
	reg, err := Open(testDictDir(), testVersion)
	if err != nil {
		fmt.Fprintln(os.Stderr, "engine test setup:", err)
		os.Exit(1)
	}
	testReg = reg
	code := m.Run()
	_ = reg.Close()
	os.Exit(code)
}

// testDictDir resolves the directory holding the committed scrabble-solver
// DAWGs: BACKEND_DICT_DIR when set (used in CI), otherwise the sibling checkout
// located relative to this test file.
func testDictDir() string {
	if dir := os.Getenv("BACKEND_DICT_DIR"); dir != "" {
		return dir
	}
	_, file, _, _ := runtime.Caller(0)
	return filepath.Join(filepath.Dir(file), "..", "..", "..", "..", "scrabble-solver", "dawg")
}

// centre returns the centre square coordinates of rs.
func centre(rs *rules.Ruleset) (row, col int) {
	return rs.Center / rs.Cols, rs.Center % rs.Cols
}

// placementsForWord lays word out from (row, col) along dir, resolving each rune
// through the ruleset's alphabet. It expresses no blanks.
func placementsForWord(t *testing.T, rs *rules.Ruleset, row, col int, dir scrabble.Direction, word string) []scrabble.Placement {
	t.Helper()
	var ps []scrabble.Placement
	for i, r := range []rune(word) {
		idx, err := rs.Alphabet.Index(string(r))
		if err != nil {
			t.Fatalf("index %q: %v", string(r), err)
		}
		rr, cc := row, col
		if dir == scrabble.Horizontal {
			cc += i
		} else {
			rr += i
		}
		ps = append(ps, scrabble.Placement{Row: rr, Col: cc, Letter: idx})
	}
	return ps
}
