import { describe, expect, it } from "vitest";
import { getKeysUpToLevel } from "./levels";
import { getWordsForLevel, validateWordList, wordsByLevel } from "./words";

describe("wordsByLevel", () => {
	it("has entries for levels 1-16", () => {
		for (let level = 1; level <= 16; level++) {
			expect(wordsByLevel[level]).toBeDefined();
			expect(Array.isArray(wordsByLevel[level])).toBe(true);
		}
	});

	it("each level has at least 8 words", () => {
		for (let level = 1; level <= 16; level++) {
			expect(wordsByLevel[level]!.length).toBeGreaterThanOrEqual(8);
		}
	});

	it("every word in level N uses only characters from that level's allKeys (no spaces)", () => {
		for (let level = 1; level <= 16; level++) {
			const allowedKeys = getKeysUpToLevel(level).filter((k) => k !== " ");
			const words = wordsByLevel[level]!;
			for (const word of words) {
				for (const char of word) {
					expect(
						allowedKeys.includes(char),
						`Word "${word}" in level ${level} contains "${char}" which is not in allowed keys [${allowedKeys.join(", ")}]`,
					).toBe(true);
				}
			}
		}
	});

	it("no word exceeds 5 characters", () => {
		for (let level = 1; level <= 16; level++) {
			const words = wordsByLevel[level]!;
			for (const word of words) {
				expect(
					word.length,
					`Word "${word}" in level ${level} has ${word.length} chars (max 5)`,
				).toBeLessThanOrEqual(5);
			}
		}
	});

	it("validateWordList confirms all words use only allowed keys", () => {
		expect(validateWordList()).toBe(true);
	});
});

describe("getWordsForLevel", () => {
	it("returns the requested count of random words from that level", () => {
		const words = getWordsForLevel(3, 5);
		expect(words).toHaveLength(5);
		for (const word of words) {
			expect(wordsByLevel[3]).toContain(word);
		}
	});

	it("returns empty array for non-existent level", () => {
		expect(getWordsForLevel(99, 5)).toEqual([]);
		expect(getWordsForLevel(0, 5)).toEqual([]);
	});

	it("can return more words than list length (with replacement)", () => {
		const words = getWordsForLevel(1, 20);
		expect(words).toHaveLength(20);
		for (const word of words) {
			expect(wordsByLevel[1]).toContain(word);
		}
	});

	it("returns unique words when count <= list length (without replacement)", () => {
		const words = getWordsForLevel(3, 5);
		const unique = new Set(words);
		expect(unique.size).toBe(5);
	});
});
