<script lang="ts">
	import type { ComputedSeries } from '$lib/chart';
	import {
		acceleration,
		APTITUDE_LEVELS,
		AptitudeLevel,
		deceleration,
		HORSE_LENGTH,
		moveLaneModifier,
		Phase,
		RunningStyle,
		skillDuration,
		speedGain,
		spotStruggleDuration,
		spotStruggleSpeed,
		Stat,
	} from '$lib/race';
	import StatChart from '$lib/StatChart.svelte';
	import SpeedDur from './SpeedDur.svelte';

	let rawPower = $state(1200);
	let rawGuts = $state(1200);
	let raceLen = $state(1600);
	let surfApt = $state(AptitudeLevel.A);
	let frontApt = $state(AptitudeLevel.A);
	let isRunaway = $state(false);
	let isCareer = $state(false);

	const careerMod = $derived(isCareer ? 400 : 0);
	const powerStat = $derived(rawPower + careerMod);
	const gutsStat = $derived(rawGuts + careerMod);
	const style = $derived(isRunaway ? RunningStyle.GreatEscape : RunningStyle.FrontRunner);

	const phases = [Phase.EarlyRace, Phase.MidRace, Phase.LateRace] as const;
	const accel = $derived(phases.map((p) => acceleration(powerStat, style, surfApt, p)));
	const decel = phases.map((p) => deceleration(p));

	const ssBoost = $derived(spotStruggleSpeed(gutsStat));
	const ssDur = $derived(spotStruggleDuration(gutsStat, frontApt));

	const lcBoost = $derived(moveLaneModifier(powerStat));
	const lcDur = $derived(Math.min(skillDuration(3, raceLen), 6));

	const uniques = [
		['Operation Cacao', 0.35, 5, Phase.MidRace],
		["All Charged! It's Go Time! (Tokyo turf)", 0.45, 5, Phase.LateRace],
	] as const;
	const skills = [
		['Fast-Paced', 0.15, 3, Phase.MidRace],
		['Professor of Curvature (mid race)', 0.35, 2.4, Phase.MidRace],
		["All Charged! It's Go Time! (inherited)", 0.25, 3, Phase.LateRace],
	] as const;

	const ssY: Array<ComputedSeries | null> = $derived([
		{
			label: 'Aptitude S',
			y: (x) => speedGain(spotStruggleSpeed(x), spotStruggleDuration(x, AptitudeLevel.S), accel[0], decel[0]) / HORSE_LENGTH,
		},
		{
			label: 'Aptitude A',
			y: (x) => speedGain(spotStruggleSpeed(x), spotStruggleDuration(x, AptitudeLevel.A), accel[0], decel[0]) / HORSE_LENGTH,
		},
		frontApt < AptitudeLevel.A
			? {
					label: `Aptitude ${AptitudeLevel[frontApt]}`,
					y: (x) => speedGain(spotStruggleSpeed(x), spotStruggleDuration(x, frontApt), accel[0], decel[0]) / HORSE_LENGTH,
				}
			: null,
	]);
	const lcY: Array<ComputedSeries | null> = $derived([
		{
			label: 'Ideal Lane Combo',
			y: (x) => speedGain(moveLaneModifier(x), lcDur, acceleration(x, style, surfApt, Phase.EarlyRace), decel[0]) / HORSE_LENGTH,
		},
	]);
	const pcRuler = $derived({
		y: speedGain(0.35, skillDuration(2.4, raceLen), accel[1], decel[1]) / HORSE_LENGTH,
		label: 'Professor of Curvature',
	});
	const ssYRule = $derived([pcRuler, { y: speedGain(lcBoost, lcDur, accel[0], decel[0]) / HORSE_LENGTH, label: 'Lane Combo' }]);
	const lcYRule = $derived([
		pcRuler,
		{ y: speedGain(ssBoost, ssDur, accel[0], decel[1]) / HORSE_LENGTH, label: 'Spot Struggle' },
	]);
</script>

<h1 class="text-4xl">Front Runner Mechanical Speed Comparator</h1>
<div class="mx-auto mt-8 grid max-w-4xl grid-cols-1 rounded-md text-center shadow-md ring md:grid-cols-8">
	<div class="m-4 md:col-span-2">
		<label for="powerStat">Power Stat</label>
		<input type="number" id="powerStat" bind:value={rawPower} class="w-full" />
	</div>
	<div class="m-4 md:col-span-2">
		<label for="gutsStat">Guts Stat</label>
		<input type="number" id="gutsStat" bind:value={rawGuts} class="w-full" />
	</div>
	<div class="m-4 md:col-span-2">
		<label for="surfaceApt">Surface Aptitude</label>
		<select id="surfaceApt" required bind:value={surfApt} class="w-full">
			{#each APTITUDE_LEVELS as apt (apt)}
				<option value={apt}>{AptitudeLevel[apt]}</option>
			{/each}
		</select>
	</div>
	<div class="m-4 md:col-span-2">
		<label for="frontApt">Front Runner Aptitude</label>
		<select id="frontApt" required bind:value={frontApt} class="w-full">
			{#each APTITUDE_LEVELS as apt (apt)}
				<option value={apt}>{AptitudeLevel[apt]}</option>
			{/each}
		</select>
	</div>
	<div class="m-4 md:col-span-2 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 md:col-span-2">
		<label for="isRunaway" class="mr-1 align-middle">Runaway</label>
		<input type="checkbox" id="isRunaway" role="switch" bind:checked={isRunaway} class="min-h-6 min-w-6 align-middle" />
	</div>
	<div class="m-4 self-center md:col-span-2">
		<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>
<span class="mt-8 block w-full text-center text-lg">Mechanics</span>
<div class="mx-auto flex w-full flex-col place-items-center md:flex-row md:justify-center">
	<SpeedDur speed={ssBoost} dur={ssDur} accel={accel[0]} decel={[decel[0], decel[1]]}>Spot Struggle</SpeedDur>
	<SpeedDur speed={lcBoost} dur={lcDur} accel={accel[0]} decel={decel[0]}>Idealized Lane Combo (DDPP)</SpeedDur>
</div>
<table class="mx-auto mt-1 table-fixed rounded-b-md border border-t-0 text-sm">
	<caption class="rounded-t-md border border-b-0">Base Acceleration</caption>
	<thead>
		<tr>
			<th class="w-32" scope="col">Early Race</th>
			<th class="w-32" scope="col">Mid Race</th>
			<th class="w-32" scope="col">Late Race</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			{#each accel as v, i (i)}
				<td class="text-center">{v.toFixed(3)} m/s²</td>
			{/each}
		</tr>
		<tr>
			{#each decel as v, i (i)}
				<td class="text-center">{v.toFixed(3)} m/s²</td>
			{/each}
		</tr>
	</tbody>
</table>
<span class="mt-8 block w-full text-center text-lg">Unique Skills</span>
<div class="mx-auto flex flex-col place-items-center md:flex-row md:justify-center">
	{#each uniques as [name, boost, dur, phase] (name)}
		<SpeedDur speed={boost} dur={skillDuration(dur, raceLen)} accel={accel[phase]} decel={decel[phase]}>{name}</SpeedDur>
	{/each}
</div>
<span class="mt-8 block w-full text-center text-lg">Inherited Uniques &amp; Other Skills</span>
<div class="mx-auto flex flex-col place-items-center md:flex-row md:justify-center">
	{#each skills as [name, boost, dur, phase] (name)}
		<SpeedDur speed={boost} dur={skillDuration(dur, raceLen)} accel={accel[phase]} decel={decel[phase]}>{name}</SpeedDur>
	{/each}
</div>
<div class="mx-auto grid h-96 grid-cols-1 py-4 md:grid-cols-2">
	<StatChart
		class="flex-1"
		stat={Stat.Guts}
		y={ssY}
		yLabel="Lengths Gained"
		range={[0, 1.5, 2.5]}
		xRule={gutsStat}
		yRule={ssYRule}
	/>
	<StatChart
		class="flex-1"
		stat={Stat.Power}
		y={lcY}
		yLabel="Lengths Gained"
		range={[0, 1.5, 2.5]}
		xRule={powerStat}
		yRule={lcYRule}
	/>
</div>
<div class="mx-auto mt-12 w-full max-w-4xl border-t pt-4 md:mt-8">
	<ul class="ml-4 list-disc">
		<li>All lengths gained include acceleration at the beginning of each speed boost and deceleration after its end.</li>
		<li>Each effect is assumed to be isolated and executed on level ground.</li>
		<li>
			Spot struggle has two numbers to distinguish ending in early race versus ending in mid race, which gives different
			deceleration values. Since spot struggle duration does not scale with race length, it is more likely to end in mid race on
			shorter races.
		</li>
		<li>
			Lane combo is idealized in the sense of assuming second lane change speed skill executes immediately after Dodging Danger
			completes, the horse is never blocked, and the horse returns to the rail in early race before the first corner.
			<ul class="ml-8 list-[revert]">
				<li>
					The move lane modifier is capped to 6 seconds, which is the approximate observed time to move from the Dodging Danger
					fixed lane back to the rail under the effect of Prudent Positioning.
				</li>
				<li>
					On medium+ tracks, with a proper gate acceleration build, Dodging Danger should realize some lane movement speed
					modifier, so the actual benefit will be more than the idealized number.
				</li>
				<li>
					Ignited Spirit WIT has a longer duration and lower lane change speed boost than Prudent Positioning, so it is likely to
					give more benefit than the idealized number.
				</li>
				<li>
					For full simulated analysis of lane combo, see <a
						href="https://lanecalc.hf-uma.net/"
						target="_blank"
						rel="noopener noreferrer">危険回避シミュ</a
					>.
				</li>
			</ul>
		</li>
	</ul>
</div>
