// Package dict loads the English test dictionary as a DAWG, preferring the serialized
// cache under testdata and falling back to building from the dictionaries submodule.
// Paths are resolved relative to the repository root so it works both from the repo root
// (commands) and from a package directory (tests).
package dict

import (
	"os"
	"path/filepath"

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

	"scrabble-solver/internal/dictdawg"
	"scrabble-solver/internal/wordlist"
)

// MinLen and MaxLen bound playable word lengths (a 15x15 board holds at most 15).
const (
	MinLen = 2
	MaxLen = 15
)

func exists(p string) bool { _, err := os.Stat(p); return err == nil }

// Root returns the repository root by walking up from the working directory to the
// directory containing go.mod, or "." if none is found.
func Root() string {
	dir, err := os.Getwd()
	if err != nil {
		return "."
	}
	for {
		if exists(filepath.Join(dir, "go.mod")) {
			return dir
		}
		parent := filepath.Dir(dir)
		if parent == dir {
			return "."
		}
		dir = parent
	}
}

// DAWGCache and WordlistPath locate the English cache file and source word list,
// relative to the repository root.
func DAWGCache() string    { return filepath.Join(Root(), "testdata", "sowpods.dawg") }
func WordlistPath() string { return filepath.Join(Root(), "dictionaries", "english", "sowpods.txt") }

// EnglishAvailable reports whether the English dictionary can be loaded (cache or source).
func EnglishAvailable() bool {
	return exists(DAWGCache()) || exists(WordlistPath())
}

// EnglishWords returns the encoded English word list (from the submodule source).
func EnglishWords() ([][]byte, error) {
	return wordlist.Read(WordlistPath(), alphabet.Latin(), MinLen, MaxLen)
}

// EnglishDAWG returns the English DAWG, loading the cache if present, otherwise building
// it from the word list and caching it (best effort).
func EnglishDAWG() (dawg.Finder, error) {
	if exists(DAWGCache()) {
		return dictdawg.Load(DAWGCache())
	}
	words, err := EnglishWords()
	if err != nil {
		return nil, err
	}
	f, err := dictdawg.Build(alphabet.Latin(), words)
	if err != nil {
		return nil, err
	}
	_ = dictdawg.Save(f, DAWGCache())
	return f, nil
}
