<script lang="ts">
	import type { ApiStationsBoard } from '@owlboard/owlboard-ts';
	import { formatUkTime, estClass, delayClassFromTimePair, isRightTime } from '$lib/utils/time';
	import { fade, slide, fly } from 'svelte/transition';
	import { flip } from 'svelte/animate';

	import ServiceDetailModal from './ServiceDetailModal.svelte';
	let isModalOpen = $state(false);
	let selectedRid = $state('');
	function handleOpenTrainDetails(rid: string) {
		selectedRid = rid;
		isModalOpen = true;
	}
	function handleCloseModal() {
		isModalOpen = false;
	}

	let { services }: { services: ApiStationsBoard.BoardService[] } = $props();

	const getRowKey = (s: ApiStationsBoard.BoardService) =>
		`${s.r}${s.sta ?? ''}${s.std ?? ''}${s.wtp ?? ''}`;
</script>

<!-- Train Detail Modal -->
<ServiceDetailModal rid={selectedRid} isOpen={isModalOpen} onClose={handleCloseModal} />

<section class="departure-board">
	<div class="header container">
		<div class="header row">
			<div class="upper-header-blank"></div>
			<div class="upper-header-text">Arr</div>
			<div class="upper-header-text">Dep</div>
		</div>
		<div class="header row">
			<div class="cell">ID</div>
			<div class="cell">Orig</div>
			<div class="cell">Dest</div>
			<div class="cell">Plt</div>
			<div class="cell">Sch</div>
			<div class="cell">Act</div>
			<div class="cell">Sch</div>
			<div class="cell">Act</div>
		</div>
	</div>
	<div class="services">
		{#each services as service (getRowKey(service))}
			{@const realArrival = formatUkTime(service.ata || service.eta)}
			{@const realDeparture = formatUkTime(service.atd || service.etd)}
			{@const realPass = formatUkTime(service.atp || service.etp)}
			<div
				class="service-block"
				animate:flip={{ duration: 400 }}
				transition:slide={{ duration: 300 }}
			>
				<div
					class="service row"
					class:passing={service.wtp}
					class:nonPax={!service.ip}
					class:cancelled={service.c}
				>
					<div class="cell id">{service.h}</div>
					<div
						class="cell orig"
						role="button"
						tabindex="0"
						aria-label="View details for train {service.r}"
						onclick={() => handleOpenTrainDetails(service.r)}
						onkeydown={(e) => {
							if (e.key === 'Enter' || e.key === ' ') {
								e.preventDefault();
								handleOpenTrainDetails(service.r);
							}
						}}
					>
						{#key service.og.t}
							<div transition:fade={{ duration: 300 }}>
								{service.og.t}
							</div>
						{/key}
					</div>
					<div
						class="cell dest"
						role="button"
						tabindex="0"
						aria-label="View details for train {service.r}"
						onclick={() => handleOpenTrainDetails(service.r)}
						onkeydown={(e) => {
							if (e.key === 'Enter' || e.key === ' ') {
								e.preventDefault();
								handleOpenTrainDetails(service.r);
							}
						}}
					>
						{#key service.dt.t}<div transition:fade={{ duration: 300 }}>{service.dt.t}</div>{/key}
					</div>
					<div class="cell plt" class:platsup={service.ps} class:platchange={service.pc}>
						{#key service.p}<div transition:fade={{ duration: 300 }}>{service.p || '-'}</div>{/key}
					</div>
					{#if service.wtp}
						<div class="cell pass">PASS</div>
						<div class="cell sch">
							{formatUkTime(service.wtp)}
						</div>
						<div
							class="cell act {estClass(service.atp, service.etp)} {delayClassFromTimePair(
								service.wtp,
								service.atp || service.etp
							)}"
						>
							{#if isRightTime(service.wtp, service.atp || service.etp)}
								RT
							{:else if service.c}
								CANC
							{:else}
								{realPass}
							{/if}
						</div>
					{:else}
						<div class="cell sch">{formatUkTime(service.sta)}</div>
						<div
							class="cell act {estClass(service.ata, service.eta)} {delayClassFromTimePair(
								service.sta,
								service.ata || service.eta
							)}"
						>
							{#if isRightTime(service.sta, service.ata || service.eta)}
								RT
							{:else if service.sta && service.c}
								CANC
							{:else}
								{realArrival}
							{/if}
						</div>
						<div class="cell sch">{formatUkTime(service.std)}</div>
						<div
							class="cell act {estClass(service.atd, service.etd)} {delayClassFromTimePair(
								service.std,
								service.atd || service.etd
							)}"
						>
							{#if isRightTime(service.std, service.atd || service.etd)}
								RT
							{:else if service.std && service.c}
								CANC
							{:else}
								{realDeparture}
							{/if}
						</div>
					{/if}
				</div>
				<div class="operator row">{service.o}</div>
				{#if service?.cr?.r}
					{#if service.c}
						<div class="cancel-reason row" transition:slide={{ duration: 300 }}>{service.cr.r}</div>
					{:else}
						<div class="cancel-reason row" transition:slide={{ duration: 300 }}>
							Part of this service has been cancelled
						</div>
					{/if}
				{:else if service?.dr?.r}
					<div class="delay-reason row" transition:slide={{ duration: 300 }}>{service.dr.r}</div>
				{/if}
			</div>
		{/each}
	</div>
</section>

<style>
	.departure-board {
		width: 100%;
		max-width: 100%;
		height: 100%;
		max-height: 100%;
		margin: 0 auto;
		box-sizing: border-box;
		overscroll-behavior-y: contain;
		overflow-y: auto;
	}

	.header.container {
		position: sticky;
		padding-top: 7px;
		top: 0;
		z-index: 10;
		background: var(--color-bg-dark);
	}

	.row.header {
		font-weight: 875;
	}
	.row.header:last-child {
		padding-bottom: 1rem;
	}

	.upper-header-blank {
		grid-column: span 4;
	}
	.upper-header-text {
		grid-column: span 2;
		text-align: center;
	}

	.row {
		display: grid;
		grid-template-columns: 10% 17% 17% 9% 12% 12% 12% 11%;
		align-items: center;
		text-align: center;
		gap: 0;
		box-sizing: border-box;
		font-family: 'Inconsolata Variable', monospace;
		font-size: clamp(1rem, 0.475rem + 2.8vw, 1.35rem);
		font-variant-ligatures: additional-ligatures;
	}

	.service.row.passing {
		font-style: italic;
		opacity: 0.25;
		font-weight: 200;
	}

	.service.row.nonPax {
		opacity: 0.25;
		font-weight: 200;
	}

	.service-block {
		width: 100%;
		max-width: 100%;
		padding-bottom: 7px;
	}

	/* Cancellation Logic */
	.service.cancelled,
	.service.cancelled .cell.orig,
	.service.cancelled .cell.dest {
		color: rgb(255, 131, 131);
	}
	.service.cancelled .cell.plt,
	.service.cancelled .cell.act {
		text-decoration: line-through;
		opacity: 0.25;
	}
	.service.cancelled .cell.sch {
		text-decoration: line-through;
	}

	/* Meta Row Styles */
	.operator.row,
	.delay-reason.row,
	.cancel-reason.row {
		grid-template-columns: 1fr;
		text-align: left;
		font-size: 0.88rem;
		font-stretch: 80%;
	}

	.cancel-reason.row {
		color: rgb(255, 131, 131);
		font-weight: 400;
		letter-spacing: -0.1ch;
	}

	.delay-reason.row {
		color: var(--delay-orange);
		font-weight: 400;
		letter-spacing: -0.1ch;
	}
	@media (min-width: 375px) {
		.operator.row,
		.delay-reason.row,
		.cancel-reason.row {
			font-size: 1.08rem;
		}
	}
	@media (min-width: 420px) {
		.operator.row,
		.delay-reason.row,
		.cancel-reason.row {
			font-size: 1.12rem;
		}
	}
	@media (min-width: 550px) {
		.operator.row,
		.delay-reason.row,
		.cancel-reason.row {
			font-size: 1.18rem;
		}
	}
	@media (min-width: 620px) {
		.operator.row,
		.delay-reason.row,
		.cancel-reason.row {
			font-size: 1.2rem;
		}
	}

	.operator.row {
		font-stretch: 110%;
		padding: 0;
		color: rgb(187, 187, 255);
	}

	/* Column Specifics */
	.cell.id {
		text-align: left;
		font-weight: 400;
		font-stretch: 85%;
		filter: brightness(0.75);
	}
	@media (min-width: 400px) {
		.cell.id {
			font-stretch: 90%;
		}
	}
	.cell.orig,
	.cell.dest {
		font-stretch: 80%;
		font-weight: 400;
		cursor: pointer;
	}
	.cell.orig {
		text-align: left;
		color: var(--location-yellow);
	}
	.cell.dest {
		text-align: right;
		color: var(--location-yellow);
	}
	@media (min-width: 350px) {
		.cell.orig,
		.cell.dest {
			font-stretch: 85%;
		}
		@media (min-width: 400px) {
			.cell.orig,
			.cell.dest {
				font-stretch: 90%;
			}
		}
		@media (min-width: 490px) {
			.cell.orig,
			.cell.dest {
				font-stretch: 95%;
			}
		}
		@media (min-width: 520px) {
			.cell.orig,
			.cell.dest {
				font-stretch: 100%;
			}
			.cell.orig {
				text-align: right;
				padding-right: 7px;
			}
			.cell.dest {
				text-align: left;
				padding-left: 7px;
			}
		}
		@media (min-width: 600px) {
			.cell.orig,
			.cell.dest {
				letter-spacing: 0.05ch;
			}
		}
	}
	.cell.plt {
		text-align: center;
		font-weight: 410;
		font-stretch: 100%;
	}
	@media (min-width: 525px) {
		.cell.plt {
			font-stretch: 110%;
		}
	}
	.cell.plt.platsup {
		font-weight: 150;
	}
	.cell.plt.platchange {
		animation: fast-pulse 2s ease-out infinite;
	}
	.pass-cell {
		text-align: center;
		font-stretch: 100%;
	}
	.cell.pass {
		grid-column: span 2;
	}
	.cell.sch,
	.cell.act {
		text-align: center;
		font-stretch: 72%;
	}
	.cell.act.delay-late {
		color: var(--delay-orange);
	}
	.cell.act.delay-early {
		color: var(--early-blue);
	}
	@media (min-width: 350px) {
		.cell.sch,
		.cell.act {
			font-stretch: 77%;
		}
	}
	@media (min-width: 400px) {
		.cell.sch,
		.cell.act {
			font-stretch: 82%;
		}
	}
	@media (min-width: 525px) {
		.cell.sch,
		.cell.act {
			font-stretch: 90%;
		}
	}
	@media (min-width: 600px) {
		.cell.sch,
		.cell.act {
			font-stretch: 100%;
		}
	}
	.cell.act.est {
		font-style: italic;
		font-weight: 300;
		opacity: 0.5;
	}

	/* Time Types */
	.cell.act.estimate {
		font-style: italic;
		opacity: 0.75;
		font-weight: 350;
	}
	.cell.act.actual {
		font-weight: 600;
	}
</style>
