package plugin

import (
	"time"

	"maunium.net/go/mautrix/id"
)

// LetterResult represents the result of a single letter in a Wordle guess.
type LetterResult int

const (
	LetterAbsent  LetterResult = iota // ⬛ not in word
	LetterPresent                     // 🟨 right letter, wrong position
	LetterCorrect                     // 🟩 right letter, right position
)

// WordleGuess stores a single guess and its evaluation.
type WordleGuess struct {
	Word       string
	PlayerID   id.UserID
	PlayerName string
	Results    []LetterResult
	Timestamp  time.Time
}

// WordleCategory identifies the language/category of a puzzle.
type WordleCategory string

const (
	WordleCategoryEN    WordleCategory = ""      // English (default)
	WordleCategoryPT    WordleCategory = "pt"    // European Portuguese
	WordleCategoryFR    WordleCategory = "fr"    // French
	WordleCategoryGames WordleCategory = "games" // Video game words (English)
)

// WordlePuzzle holds all state for one day's puzzle.
type WordlePuzzle struct {
	PuzzleID     string // YYYY-MM-DD
	PuzzleNumber int
	RoomID       id.RoomID
	Answer       string // uppercased
	WordLength   int
	MaxGuesses   int
	Category     WordleCategory
	Guesses      []WordleGuess
	Solved       bool
	Failed       bool
	StartedAt    time.Time
	SolvedAt     *time.Time
	LetterStates map[rune]LetterResult // best known state per letter
}

// WordlePlayerStat tracks a player's all-time Wordle stats.
type WordlePlayerStat struct {
	UserID         id.UserID
	DisplayName    string
	TotalGuesses   int
	PuzzlesPlayed  int
	PuzzlesSolved  int
	WinningGuesses int
}

// scoreGuess evaluates a guess against the answer using the standard
// two-pass Wordle algorithm for correct duplicate-letter handling.
func scoreGuess(guess, answer string) []LetterResult {
	n := len(answer)
	results := make([]LetterResult, n)
	pool := make([]rune, 0, n)

	guessRunes := []rune(guess)
	answerRunes := []rune(answer)

	// First pass: mark exact matches (Correct).
	used := make([]bool, n)
	for i := 0; i < n; i++ {
		if guessRunes[i] == answerRunes[i] {
			results[i] = LetterCorrect
			used[i] = true
		}
	}

	// Build pool of unmatched answer letters.
	for i := 0; i < n; i++ {
		if !used[i] {
			pool = append(pool, answerRunes[i])
		}
	}

	// Second pass: mark Present or Absent.
	for i := 0; i < n; i++ {
		if results[i] == LetterCorrect {
			continue
		}
		found := false
		for j, r := range pool {
			if guessRunes[i] == r {
				results[i] = LetterPresent
				pool = append(pool[:j], pool[j+1:]...)
				found = true
				break
			}
		}
		if !found {
			results[i] = LetterAbsent
		}
	}

	return results
}

// updateLetterStates updates the keyboard state map with results from a guess.
// A letter's state only upgrades: Absent → Present → Correct.
func updateLetterStates(states map[rune]LetterResult, guess string, results []LetterResult) {
	for i, r := range []rune(guess) {
		existing, ok := states[r]
		if !ok || results[i] > existing {
			states[r] = results[i]
		}
	}
}
