package engine

import "fmt"

// SetupTile is one tile of a variant's full bag, decoded for the first-move draw
// (docs/ARCHITECTURE.md §6): its concrete letter (or the blank marker), a blank
// flag, and its draw rank. Lower rank wins the draw — a blank ranks above every
// letter, and letters rank by alphabet index, so the tile closest to the start of
// the alphabet ("A") wins. It is dictionary-independent, built from the variant's
// solver ruleset alone.
type SetupTile struct {
	// Letter is the concrete character (the case the solver ruleset emits), or
	// the blank marker "?" for a blank.
	Letter string
	// Blank reports whether the tile is a blank.
	Blank bool
	// Rank orders the draw: BlankRank for a blank (best), else the letter's
	// alphabet index (0 = closest to "A").
	Rank int
}

// BlankRank is the first-move draw rank of a blank: below every letter index, so a
// blank always beats a lettered tile, matching the official rule that a blank
// supersedes all letters.
const BlankRank = -1

// SetupBag returns variant's full tile bag — every lettered tile expanded by its
// count, plus one entry per blank — decoded for the first-move seeding draw. The
// order is deterministic (alphabet order, blanks last); callers shuffle it with
// their own entropy. It needs no dictionary, so it is built from the variant's
// ruleset alone and reports ErrUnknownVariant for an unrecognised variant.
func SetupBag(v Variant) ([]SetupTile, error) {
	rs, ok := v.ruleset()
	if !ok {
		return nil, fmt.Errorf("%w: %d", ErrUnknownVariant, v)
	}
	bag := make([]SetupTile, 0, 128)
	for i, n := range rs.Counts {
		ch, err := rs.Alphabet.Character(byte(i))
		if err != nil {
			// An offered variant's alphabet never yields a bad index; skip defensively.
			continue
		}
		for range n {
			bag = append(bag, SetupTile{Letter: ch, Rank: i})
		}
	}
	for range rs.Blanks {
		bag = append(bag, SetupTile{Letter: blankLetter, Blank: true, Rank: BlankRank})
	}
	return bag, nil
}
