import {anyCharOf, spaces1, string, whitespace} from "parjs";
import {between, exactly, manySepBy, stringify, then} from "parjs/combinators";
import {Range} from "immutable";
import fs from "fs";

export type Race = [number, number];

const timeName = string('Time:').pipe(then(spaces1()));
const distanceName = string('Distance:').pipe(then(spaces1()));

const numbersParser = anyCharOf("0123456789").pipe(manySepBy(whitespace().pipe(exactly(2))), stringify());
const timeParser = numbersParser.pipe(between(timeName, whitespace()));
const distanceParser = numbersParser.pipe(between(distanceName, whitespace()));

const parser = timeParser.pipe(then(distanceParser));

export class BoatRace {
	private readonly race: Race;

	constructor(input: string) {
		const [times, distances] = parser.parse(input).value;
		this.race = [parseInt(times), parseInt(distances)];
	}

	numberOfWinningMethods = (race: Race): number => {
		const [time, distance] = race;

		const canWin = (holdingTime: number) => ((time - holdingTime) * holdingTime) > distance;

		const range = Range(0, time).filter(canWin).cacheResult();
		return range.size || 0;
	}

	public totalNumberOfWaysToBeatRace(): number {
		return this.numberOfWinningMethods(this.race);
	}
}

export const runDaySix = () => {
	const input = fs.readFileSync('./inputs/day_six_input.txt', 'utf-8').trimEnd();
	const races = new BoatRace(input);
	console.log(races.totalNumberOfWaysToBeatRace());
}