#!/usr/bin/env -S deno run --allow-read

import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";

import {
	Dict,
	ExplorerGuesser,
	Guessing,
	LoggingStrategy,
	ReducingGuesser,
	Runner,
	Simulator,
	TableLogging,
	VerboseLogging,
} from "./lib/lib.ts";

import { francais } from "../data/data.ts";

async function main() {
	const args = await new Command().name("simulation")
		.description(
			"Program to simulate TUSMO game with guesser controller.",
		)
		.option(
			"-f, --file <path:string>",
			"Sets dictionnary to use words from (defaults to internal french dict).",
		).option(
			"-n, --length <length:number>",
			"Length of the word to use from the dictionnary.",
		).option(
			"-w, --wait <wait:number>",
			"Time to wait between guesses, in ms.",
			{ default: 0 },
		).option(
			"-t, --target <target:string>",
			"Target word to search for.",
		).option(
			"-g, --guesser <guesser:string>",
			`Guesser to use, available are ${[...guessers.keys()]}.`,
			{ default: "reducing" },
		)
		.option(
			"-l, --logger <logger:string>",
			`Logger to use, available are ${[...loggers.keys()]}.`,
			{ default: "verbose" },
		)
		.parse(Deno.args);
	const length = args.options.length ?? args.options.target?.length ?? 6;

	let dict = Dict.from_lines(francais, length);
	if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, length);

	const guesser = guessers.get(args.options.guesser)!(dict);
	let game = Simulator.from_dict_rand(dict);
	if (args.options.target !== undefined) game = new Simulator(validate_target(args.options.target, length));
	console.log("Target is", game.word);
	console.log();

	const runner = new Runner(game, guesser, new TableLogging(), args.options.wait);
	await runner.play_all();
}

function validate_target(target: string, length: number) {
	if (target.length !== length) throw new Error("Invalid target length");
	return target.toLowerCase();
}

const guessers = new Map<string, (dict: Dict) => Guessing>([
	["explorer", (dict: Dict) => new ExplorerGuesser(dict)],
	["reducing", (dict: Dict) => new ReducingGuesser(dict)],
]);

const loggers = new Map<string, LoggingStrategy>([
	["verbose", new VerboseLogging()],
	["table", new TableLogging()],
]);

if (import.meta.main) await main();
