<script lang="ts">
  import { browser, building, dev } from '$app/environment';
  import { page } from '$app/state';
  import { S } from '$lib';
  import { normalisePlaceName, operators } from './aliases';
  import LineGlyph from './assets/LineGlyph.svelte';
  import Pictogram from './assets/Pictogram.svelte';
  import { Mode, type StoptimesResponse } from './motis-types';
  import { m } from './paraglide/messages';
  import {
    blacklistedAgencyURLs,
    getNotices,
    getPictogram,
    stopTimeShouldRenderGlyph,
    stopTimeToShortName,
  } from './RenderUtil';

  let relativeSecondPrecision = $derived(
    ['seconds', 'second', 'sec', 'secs', 's', '2'].includes(
      building ? null! : page.url.searchParams.get('relative')!
    )
  );
  let isRelativeTime = $derived(
    relativeSecondPrecision ||
      ['1', 'true'].includes(
        building ? null! : page.url.searchParams.get('relative')!
      )
  );
  /** only if isRelativeTime is true */
  let now = $state(0);
  const updateNow = () => {
    now = Date.now();
    setTimeout(updateNow, 33);
  };
  $effect(() => (isRelativeTime ? updateNow() : void 0));

  let {
    stopTimes,
    isArrivals = false,
    placeName = '',
    placeId,
    isResultsPage = true,
    setSearch = (q) => void 0,
  }: {
    stopTimes: null | StoptimesResponse;
    isArrivals?: boolean;
    placeName?: string;
    isResultsPage?: boolean;
    placeId: string | null;
    setSearch: (query: string) => void;
  } = $props();
  const timeRelative = (ms: number, relativeTo = now) => {
    const _totalMillis = ms - relativeTo;
    const totalMillis = Math.abs(_totalMillis);
    const totalSeconds = totalMillis / 1000;
    const totalMinutes = totalSeconds / 60;
    const totalHours = totalMinutes / 60;
    const hours = Math.floor(totalHours);
    const minutes = Math.floor(totalMinutes) - hours * 60;
    const seconds = Math.floor(totalSeconds) - hours * 60 * 60 - minutes * 60;
    const results = [] as string[];
    if (hours)
      results.push(
        `${m.hours({
          hours,
        })}`
      );
    if (hours || minutes) results.push(`${m.minutes({ minutes })}`);
    if (seconds && relativeSecondPrecision)
      results.push(`${m.seconds({ seconds })}`);
    if (results.length > 1) {
      const [r, l] = [results.pop()!, results.pop()!];
      results.push(
        m.time_joiner({
          l,
          r,
        })
      );
    }
    const relTime =
      results.length === 1
        ? results[0]
        : results.length === 0
          ? ''
          : results.reduce((pv, cv) => m.time_joiner2({ l: pv, r: cv }));
    if (relTime === '')
      return m.time_immediate({
        isPastTense: _totalMillis < 0 ? 'true' : 'false',
      });
    if (_totalMillis < 0)
      return m.past_time({
        relTime,
      });
    else
      return m.future_time({
        relTime,
      });
  };
  const localTime = async (
    time: Date,
    forceAbsolute = false,
    relativeTo = now
  ) => {
    const offset = parseFloat(
      browser
        ? // Browsers like Librewolf love patching time to be a fixed timezone, breaking us.
          (localStorage.getItem(
            isRelativeTime && !forceAbsolute
              ? 'relative-offset-time'
              : 'offset-time'
          ) ?? '0')
        : // @ts-ignore
          ((typeof process !== 'undefined' ? process.env : undefined)?.env[
            isRelativeTime && !forceAbsolute
              ? 'PRIVATE_RELATIVE_TIME_OFFSET'
              : 'PRIVATE_SERVER_TIMEZONE'
          ] ?? '0')
    );
    if (isRelativeTime && !forceAbsolute) {
      return timeRelative(time.getTime() - offset * 60 * 60 * 1000, relativeTo);
    } else {
      let hours = time.getHours() + Math.floor(offset);
      const minutes = time.getMinutes() + Math.floor((offset % 1) * 60);
      const seconds =
        time.getSeconds() + Math.floor(((offset % 1) * 60) % 1) * 60;
      if (hours < 0) while (hours < 0) hours += 24;
      else if (hours >= 24) while (hours >= 24) hours -= 24;
      return (
        hours.toString().padStart(2, '0') +
        ':' +
        minutes.toString().padStart(2, '0') +
        (seconds !== 0 ? `:${seconds.toString().padStart(2, '0')}` : '')
      );
    }
  };
</script>

{#snippet renderLocalTime(
  time: Date,
  forceAbsolute = false
)}{#await localTime(time, forceAbsolute, now)}{isRelativeTime && !forceAbsolute
      ? timeRelative(time.getTime(), now)
      : time.getUTCHours() +
        ':' +
        time.getUTCMinutes() +
        (time.getUTCSeconds() !== 0 ? `:${time.getUTCSeconds()}` : '') +
        ' UTC'}{:then t}{t}{/await}{/snippet}

{#if stopTimes}
  {#each stopTimes.stopTimes
    // garbage data
    .filter((v) => !blacklistedAgencyURLs.includes(v.agencyUrl)) as departure}
    {@const expectedTime =
      new Date(
        (isArrivals
          ? departure.place.scheduledArrival
          : departure.place.scheduledDeparture) ?? '0'
      ).getTime() /
      1000 /
      60}
    {@const receivedTime =
      new Date(
        (isArrivals ? departure.place.arrival : departure.place.departure) ??
          '0'
      ).getTime() /
      1000 /
      60}
    {@const delayMinutes = receivedTime - expectedTime}
    {@const routeShortName = stopTimeToShortName(departure)}
    {@const pictogram = getPictogram(departure.mode)}
    {@const notices = getNotices(departure, delayMinutes, isArrivals)}
    {@const situationIsBad = notices.find((v) => v[0].includes('Attention'))}
    <div
      class={{
        'p-4 pr-3 sm:pr-4 md:p-6 md:pr-6 rounded-xl': true,
        'bg-[#28282C]': !situationIsBad,
        'bg-[#452525]': situationIsBad,
      }}
      data-data={dev ? JSON.stringify(departure, null, 2) : undefined}
    >
      <div class="flex gap-1 md:items-center md:flex-row flex-col flex-wrap">
        <div class="pictoline flex gap-1 md:items-center flex-r">
          {#if pictogram}
            <Pictogram which={pictogram} />
          {/if}
          {#if stopTimeShouldRenderGlyph(departure, routeShortName)}
            <LineGlyph
              currentColor="#fff"
              kind={routeShortName}
              negative={false}
              dark
            />
          {:else}
            <span
              class="ml-1 -mr-0.5 md:mt-0.5 font-sbb-typo text-nowrap font-bold"
            >
              {routeShortName}
            </span>
          {/if}
          <span class="ml-1 -mr-0.5 md:mt-0.5 font-sbb-typo">
            <!-- {isArrivals ? m.from() : m.to()} -->
            {m.to()}
            <span class="font-semibold"
              >{normalisePlaceName(departure.headsign)}</span
            >
          </span>
        </div>
        <div class="flex-1"></div>
        {#if departure.place.scheduledTrack && departure.place.track}
          <span
            class={{
              'ml-1 mt-0.5 font-[SBB,Inter,system-ui,sans-serif]': true,
              'text-red-400':
                departure.place.scheduledTrack !== departure.place.track,
            }}
          >
            {#if departure.place.name !== placeName}{`${
                departure.place.name === placeName + ', Bahnhof'
                  ? placeName + ', Busbahnhof'
                  : departure.place.name
              }, `}
            {/if}<span class="font-semibold"
              >{m.station_location({
                track: departure.place.track,
                mode: departure.mode,
              })}</span
            >
          </span>
        {:else if departure.place.name !== placeName}{departure.place.name ===
          placeName + ', Bahnhof'
            ? placeName + ', Busbahnhof'
            : departure.place.name}
        {/if}
      </div>
      <div class="flex gap-1 items-center">
        {departure.cancelled
          ? m.antsy_weird_cowfish_wish() + ' '
          : ''}{isRelativeTime && Math.abs(expectedTime - receivedTime) < 1
          ? isArrivals
            ? m.arrival_in()
            : m.departure_in()
          : isArrivals
            ? m.arrival_at()
            : m.departure_at()}
        {#if Math.abs(expectedTime - receivedTime) < 1}
          <span class="font-bold">
            {@render renderLocalTime(new Date(receivedTime * 60 * 1000))}
          </span>
        {:else}
          <span class="line-through">
            {@render renderLocalTime(new Date(expectedTime * 60 * 1000), true)}
          </span>
          <span class="font-bold">
            {@render renderLocalTime(new Date(receivedTime * 60 * 1000), true)}
          </span>
          {#if isRelativeTime}
            <span class="opacity">
              ({@render renderLocalTime(new Date(receivedTime * 60 * 1000))})
            </span>
          {/if}
        {/if}
      </div>
      {#if notices.length !== 0}
        <div class="notices pt-2 flex flex-col gap-1">
          {#each notices as notice}
            <div class="flex items-center gap-2">
              {#each notice[0] as pictogram}<Pictogram
                  which={pictogram}
                />{/each}
              <span class="ml-0.5">
                {notice[1]}
              </span>
            </div>
          {/each}
        </div>
      {/if}
      <!-- <pre>{JSON.stringify(departure, null, 2)}</pre> -->
      {#if departure.agencyName}
        <small class="-mb-1 mt-2 block opacity-70"
          >{m.operated_by({
            operator: operators.has(departure.agencyName)
              ? operators.get(departure.agencyName)!
              : departure.agencyName,
          })}{#if departure.agencyName === 'DB Fernverkehr AG'}
            {' '}
            <b>·</b>
            {m.line_number_accuracy()}{/if}</small
        >
      {/if}
    </div>
  {/each}
{:else}
  <div class="flex items-center justify-center">
    {#if (placeName || placeId) && isResultsPage}
      <div class="results max-w-2xl relative">
        <h2 class="text-2xl opacity-90">{m.no_results_title()}</h2>
        <p>
          {#each m
            .no_results_body({ stationName: placeName ?? placeId })
            .split('*') as part, idx}{#if idx % 2 === 0}{part}{:else}<b
                >{part}</b
              >{/if}{/each}
        </p>
      </div>
    {:else if placeId}
      <div
        class="flex flex-col gap-2 justify-stretch w-full no-scroll-body"
        style="--shimmer-w: 2000px"
      >
        {#each Array(30) as _}
          <div class="h-[7.575rem] relative bg-[#28282C] rounded-xl">
            <div class="w-full h-full skeleton-shimmer rounded-xl"></div>
          </div>
        {/each}
      </div>
    {:else}
      <div class="results max-w-2xl relative">
        <h2 class="text-2xl opacity-90">{m.welcome_title()}</h2>
        <p class="pb-1">
          {m.welcome_body_1()}
        </p>
        <div
          class="pb-1 pt-3 flex flex-wrap gap-2 w-full max-w-2xl justify-center"
        >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Zürich HB')}>Zürich HB</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Bielefeld Hbf')}>Bielefeld Hbf</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Berlin Hbf')}>Berlin Hbf</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Hamburg Hbf')}>Hamburg Hbf</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Bern')}>Bern</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Basel SBB')}>Basel SBB</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Genève-Aéroport')}>Genève-Aéroport</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Max-Weber-Platz')}>Max-Weber-Platz</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Lindau-Reutin')}>Lindau-Reutin</button
          >
          <button
            class="{S.button('secondary').replace(
              'not-disabled:bg-[#0000]',
              'not-disabled:bg-[#2E2E3299]'
            )} flex-1 text-nowrap p-3 min-w-max"
            onclick={() => setSearch('Lindau-Reutin')}>Lindau-Reutin</button
          >
        </div>
      </div>
    {/if}
  </div>
{/if}
