import WordPicker from "./WordPicker";

export enum CharState {
    Correct,
    Misplaced,
    Wrong,
    Unknow
}

class Wordle {
    private static words_size = 5;
    private word: string;
    private words: string[];

    constructor(wordPicker: { getWord: () => string, getWordList: () => string[]; }) {
        this.ensureWordLength(wordPicker.getWord());
        this.word = wordPicker.getWord();
        this.words = wordPicker.getWordList();
    }

    private ensureWordLength(word: string): word is string {
        return word.length === Wordle.words_size;
    }
    public static done(states: CharState[]) {
        return states.every((state) => state === CharState.Correct);
    }
    public static get_word_size() {
        return this.words_size;
    }
    private checkIfMisplaced(guess: string, states: CharState[], index: number) {
        if (states[index] !== CharState.Unknow) {
            return false;
        }
        const qtd_chars_guess = guess
            .slice(0, index + 1)
            .split("")
            .reduce<number>((sum, char) => {
                return sum + (
                    char === guess[index]
                        ? 1
                        : 0
                );
            }, 0);
        const qtd_chars = this.word
            .split("")
            .reduce<number>((sum, char, internal_index) => {
                return sum + (
                    char === guess[index] && states[internal_index] !== CharState.Correct
                        ? 1
                        : 0
                );
            }, 0);
        return qtd_chars >= qtd_chars_guess;
    }
    private checkAllCorrets(guess: string, states: CharState[]) {
        for (let index = 0; index < Wordle.words_size; index++) {
            const word_char = this.word.at(index);
            const guess_char = guess.at(index) ?? "?";

            if (word_char === guess_char) {
                states[index] = CharState.Correct;
            }
        }
        return states;
    }
    private checkAllMismatches(guess: string, states: CharState[]) {
        for (let index = 0; index < Wordle.words_size; index++) {
            if (this.checkIfMisplaced(guess, states, index)) {
                states[index] = CharState.Misplaced;
            }
        }
        return states;
    }
    private checkAllWrongs(states: CharState[]) {
        for (let index = 0; index < Wordle.words_size; index++) {
            if (states[index] === CharState.Unknow) {
                states[index] = CharState.Wrong;
            }
        }
        return states;
    }
    private createStates(): CharState[] {
        let states = Array(Wordle.words_size);
        for (let index = 0; index < Wordle.words_size; index++) {
            states[index] = CharState.Unknow;
        }
        return states;
    }
    public checkWord(guess: string): CharState[] {
        if (!this.ensureWordLength(guess)) {
            throw new Error("Word is the wrong length");
        }
        if (!this.ensureWordPossible(guess)) {
            throw new Error(`${guess} is not on the list`);
        }
        let states: CharState[] = this.createStates();
        this.checkAllCorrets(guess, states);
        this.checkAllMismatches(guess, states);
        this.checkAllWrongs(states);
        return states;
    }
    private ensureWordPossible(guess: string) {
        return this.words.includes(guess);
    }
    public getWord() {
        return this.word;
    }

}

export default Wordle;
