<script lang="ts">
	import type { ComputedSeries } from '$lib/chart';
	import { AptitudeLevel, duelSpeedMod, inverseSpurtSpeed, RunningStyle, spurtSpeed, Stat } from '$lib/race';
	import StatChart from '$lib/StatChart.svelte';
	import CalcInfo from '../CalcInfo.svelte';

	const aptsList = Object.entries(AptitudeLevel).filter(([, val]) => typeof val === 'number');
	const stylesList = [
		['Front Runner', RunningStyle.FrontRunner],
		['Pace Chaser', RunningStyle.PaceChaser],
		['Late Surger', RunningStyle.LateSurger],
		['End Closer', RunningStyle.EndCloser],
		['Great Escape', RunningStyle.GreatEscape],
	] as const;
	const skillSpeeds = [0.45, 0.35, 0.25, 0.15] as const;

	let rawSpeed: number = $state(1200);
	let rawGuts: number = $state(1200);
	let style: RunningStyle = $state(RunningStyle.FrontRunner);
	let opponentStyle: RunningStyle = $state(RunningStyle.PaceChaser);
	let distanceApt: AptitudeLevel = $state(AptitudeLevel.S);
	let raceLen: number = $state(2000);
	let isCareer: boolean = $state(false);

	const careerMod = $derived(isCareer ? 400 : 0);
	const speedStat = $derived(rawSpeed + careerMod);
	const gutsStat = $derived(rawGuts + careerMod);
	const speed = $derived(spurtSpeed(speedStat, gutsStat, style, distanceApt, raceLen));
	const duelBonus = $derived(duelSpeedMod(gutsStat));

	const sProf = $derived([
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.FrontRunner, AptitudeLevel.S, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.PaceChaser, AptitudeLevel.S, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.LateSurger, AptitudeLevel.S, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.EndCloser, AptitudeLevel.S, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.GreatEscape, AptitudeLevel.S, raceLen) - careerMod,
	]);
	const aProf = $derived([
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.FrontRunner, AptitudeLevel.A, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.PaceChaser, AptitudeLevel.A, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.LateSurger, AptitudeLevel.A, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.EndCloser, AptitudeLevel.A, raceLen) - careerMod,
		inverseSpurtSpeed(speed, gutsStat, RunningStyle.GreatEscape, AptitudeLevel.A, raceLen) - careerMod,
	]);
	const skillProf = $derived(
		skillSpeeds.map((v) => [v, inverseSpurtSpeed(speed + v, gutsStat, opponentStyle, AptitudeLevel.S, raceLen) - careerMod]),
	);

	const speedChart: Array<ComputedSeries | null> = $derived([
		{ label: 'Aptitude S', y: (x) => spurtSpeed(x, gutsStat, style, AptitudeLevel.S, raceLen) },
		{
			label: `Aptitude ${AptitudeLevel[distanceApt]} + Dueling`,
			y: (x) => spurtSpeed(x, gutsStat, style, distanceApt, raceLen) + duelBonus,
		},
		distanceApt !== AptitudeLevel.S
			? { label: `Aptitude ${AptitudeLevel[distanceApt]}`, y: (x) => spurtSpeed(x, gutsStat, style, distanceApt, raceLen) }
			: null,
	]);
	const gutsChart: Array<ComputedSeries | null> = $derived([
		{ label: 'Aptitude S', y: (x) => spurtSpeed(speedStat, x, style, AptitudeLevel.S, raceLen) },
		{
			label: `Aptitude ${AptitudeLevel[distanceApt]} + Dueling`,
			y: (x) => spurtSpeed(speedStat, x, style, distanceApt, raceLen) + duelSpeedMod(x),
		},
		distanceApt !== AptitudeLevel.S
			? { label: `Aptitude ${AptitudeLevel[distanceApt]}`, y: (x) => spurtSpeed(speedStat, x, style, distanceApt, raceLen) }
			: null,
	]);

	const range: [number, number] = $derived([
		spurtSpeed(200, gutsStat, RunningStyle.GreatEscape, AptitudeLevel.C, raceLen),
		spurtSpeed(2000, gutsStat, RunningStyle.EndCloser, AptitudeLevel.S, raceLen) + duelBonus,
	]);
</script>

<h1 class="text-4xl">Spurt Speed Calculator</h1>
<div class="mx-auto mt-8 grid max-w-4xl grid-cols-1 rounded-md text-center shadow-md ring md:grid-cols-4">
	<div class="m-4">
		<label for="speedStat">Speed Stat</label>
		<input type="number" id="speedStat" required bind:value={rawSpeed} class="w-full" />
	</div>
	<div class="m-4">
		<label for="gutsStat">Guts Stat</label>
		<input type="number" id="gutsStat" required bind:value={rawGuts} class="w-full" />
	</div>
	<div class="m-4">
		<label for="style">Style</label>
		<select id="style" required bind:value={style} class="w-full">
			{#each stylesList as [name, style] (style)}
				<option value={style}>{style === RunningStyle.GreatEscape ? 'Great Escape (Runaway)' : name}</option>
			{/each}
		</select>
	</div>
	<div class="m-4">
		<label for="distanceApt">Distance Aptitude</label>
		<select id="distanceApt" required bind:value={distanceApt} class="w-full">
			{#each aptsList.toReversed() as [name, val] (val)}
				<option value={val}>{name}</option>
			{/each}
		</select>
	</div>
	<div class="m-4 md:col-start-2">
		<label for="raceLen">Race Distance</label>
		<input type="number" id="raceLen" required min="1000" max="3600" step="100" bind:value={raceLen} class="w-full" />
	</div>
	<div class="m-4 self-center">
		<label for="isCareer" class="mr-1 align-middle">In Career</label>
		<input type="checkbox" id="isCareer" role="switch" bind:checked={isCareer} class="min-h-6 min-w-6 align-middle" />
	</div>
</div>
<div class="mx-auto mt-8 flex max-w-3xl flex-col md:flex-row">
	<CalcInfo title="Target Spurt Speed" class="flex-1">{speed.toFixed(3)} m/s</CalcInfo>
	<CalcInfo title="Dueling Bonus" class="flex-1">+{duelBonus.toFixed(3)} m/s</CalcInfo>
</div>
{#each [[AptitudeLevel.A, aProf] as const, [AptitudeLevel.S, sProf] as const] as [level, inv] (level)}
	<div class="mx-auto max-w-3xl">
		<span class="mt-8 block w-full">
			With {AptitudeLevel[level]} proficiency, the equivalent speed is
		</span>
		<div class="flex flex-col md:flex-row">
			{#each stylesList as [styleName, s] (s)}
				<CalcInfo title={styleName} class={['flex-1', { 'border-2': s === style }]}>{inv[s]}</CalcInfo>
			{/each}
		</div>
	</div>
{/each}
<div class="mx-auto max-w-3xl">
	<span class="mt-8 block w-full">
		While a speed skill is active, the equivalent speed for a distance S
		<select id="opponentStyle" required bind:value={opponentStyle}>
			{#each stylesList as [name, style] (style)}
				<option value={style}>{style === RunningStyle.GreatEscape ? 'Great Escape (Runaway)' : name}</option>
			{/each}
		</select>
		is
	</span>
	<div class="flex flex-col md:flex-row">
		{#each skillProf as [v, inv] (v)}
			<CalcInfo title={`+${v.toFixed(2)}`} class="flex-1">{inv}</CalcInfo>
		{/each}
	</div>
</div>
<div class="mx-auto grid h-96 grid-cols-1 py-4 md:grid-cols-2">
	<StatChart stat={Stat.Speed} y={speedChart} yLabel="Spurt Speed (m/s)" xRule={speedStat} {range} />
	<StatChart stat={Stat.Guts} y={gutsChart} yLabel="Spurt Speed (m/s)" xRule={gutsStat} {range} />
</div>
