export class Dict {
	words;
	letters;
	length;

	constructor(words: Set<string>, length: number) {
		this.words = words;
		this.length = length;
		this.letters = new Set([...words.values()].map((w) => w.split("")).flat());
	}

	static from_lines(lines: string[], length: number) {
		const words = new Set<string>();
		for (const word of lines) {
			const word_ = word.trim().toLowerCase();
			if (word_.length !== length) continue;
			if (contains_any(word_, [" ", "-", "."])) continue;
			words.add(remove_accents(word_));
		}
		return new Dict(words, length);
	}

	static async from_text_file(path: string, length: number) {
		const content = await Deno.readTextFile(path);
		return Dict.from_lines(content.split("\n"), length);
	}

	constraint(at: number, letter: string) {
		const to_delete = new Set<string>();
		for (const word of this.words.values()) if (word[at] !== letter) to_delete.add(word);
		for (const item of to_delete) this.words.delete(item);
		return to_delete.size;
	}

	[Symbol.for("Deno.customInspect")]() {
		return `Dict { ${this.words.size} words, ${this.letters.size} letters }`;
	}

	clone() {
		const words = new Set(this.words.values());
		return new Dict(words, this.length);
	}

	sample(quantity: number) {
		const words = new Set<string>();
		const this_words = [...this.words.values()];
		while (words.size < quantity) {
			const index = Math.floor(Math.random() * this_words.length);
			words.add(this_words[index]);
		}
		return new Dict(words, this.length);
	}
}

export function contains_any(text: string, words: string[]) {
	for (const word of words) if (text.includes(word)) return true;
	return false;
}

export function remove_accents(text: string) {
	const accents = [
		...[["à", "a"], ["â", "a"], ["ä", "a"]],
		...[["ç", "c"]],
		...[["é", "e"], ["è", "e"], ["ê", "e"], ["ë", "e"]],
		...[["î", "i"], ["ï", "i"]],
		...[["ô", "o"], ["ö", "o"]],
		...[["û", "u"]],
	];
	let result = text;
	for (const [accent, alternative] of accents) result = result.replaceAll(accent, alternative);
	return result;
}
