<script>
  export let station = '';
  export let title = 'Loading...';
  import { onMount } from 'svelte';
  import AlertBar from './alert-bar.svelte';
  import StaffTrainDetail from '$lib/ldb/staff-train-detail.svelte';
  import Loading from '$lib/navigation/loading.svelte';
  import Nav from '$lib/navigation/nav.svelte';
  import { uuid } from '$lib/stores/uuid';

  let requestedStation;
  $: requestedStation = station;

  let jsonData = {};
  let services = [];
  let dataAge = null;
  let isLoading = true;
  let alerts = [];

  $: {
    if (jsonData?.GetBoardResult?.generatedAt) {
      dataAge = new Date(jsonData.GetBoardResult.generatedAt);
    }

    if (jsonData?.GetBoardResult?.trainServices?.service) {
      services = jsonData.GetBoardResult.trainServices.service;
    } else {
      services = [];
    }

    if (jsonData?.GetBoardResult?.locationName) {
      title = jsonData.GetBoardResult.locationName;
    } else {
      title = 'Loading Board';
    }

    if (jsonData?.GetBoardResult?.nrccMessages) {
      alerts = processNrcc(jsonData.GetBoardResult?.nrccMessages?.message);
    }
  }

  async function fetchData() {
    isLoading = true; // Set loading state
    try {
      console.log(`Requested Station: ${requestedStation}`);
      const url = `https://owlboard.info/api/v2/live/station/${requestedStation}/staff`;
      const opt = {
        method: 'GET',
        headers: {
          uuid: $uuid
        }
      };
      const data = await fetch(url, opt);
      jsonData = await data.json();
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      isLoading = false; // Clear loading state
    }
  }

  async function getReasonCodeData(code) {
    const url = `https://owlboard.info/api/v2/ref/reasonCode/${code}`;
    const res = await fetch(url);
    const json = await res.json();
    return json;
  }

  async function generateServiceData(service) {
    const timeDetails = await parseTimes(service);
    let serviceData = {
      from: await parseLocation(service.origin),
      to: await parseLocation(service.destination),
      length: await getTrainLength(service),
      platform: await parsePlatform(service?.platform || 'undefined'),
      platformHidden: service?.platformIsHidden === 'true',
      schArr: timeDetails.schArr,
      expArr: timeDetails.expArr,
      schDep: timeDetails.schDep,
      expDep: timeDetails.expDep,
      isEarlyArr: timeDetails.earArr,
      isLateArr: timeDetails.delArr,
      isEarlyDep: timeDetails.earDep,
      isLateDep: timeDetails.delDep,
      isCancelledDep: false,
      isCancelled: Boolean(service?.isCancelled),
      isDelayed: service?.arrivalType === 'Delayed',
      isArrDelayed: service?.arrivalType === 'Delayed',
      isDepDelayed: service?.departureType === 'Delayed',
      isNonPublic: service?.isPassengerService === "false" ? true : false
    };
    return serviceData;
  }

  async function getTrainLength(service) {
    if (service?.length) {
      return parseInt(service?.length);
    } else if (service?.formation?.coaches) {
      return service.formation.coaches.coach.length;
    }
    return null;
  }

  async function parseLocation(location) {
    if (!Array.isArray(location.location)) {
      //console.log(location.location?.tiploc)
      return location.location?.tiploc;
    }
    let locations = [];
    for (const singleLocation of location?.location) {
      locations.push(singleLocation?.tiploc);
    }
    return locations.join(' & ');
  }

  async function parsePlatform(platform) {
    if (!platform) {
      return '-';
    }
    if (platform === 'TBC' || platform == 'undefined') {
      return '-';
    }
    return {
      number: platform
    };
  }

  function parseTimes(service) {
    let schArr = new Date(service?.sta);
    let expArr = new Date(service?.eta || service?.ata);
    let schDep = new Date(service?.std);
    let expDep = new Date(service?.etd || service?.atd);
    let isEarlyArr = false,
      isDelayedArr = false,
      isArr = false;
    let isEarlyDep = false,
      isDelayedDep = false,
      isDep = false;
    const timeDifferenceThreshold = 60 * 1000; // 60 seconds in milliseconds
    if (expArr - schArr < -timeDifferenceThreshold) {
      isEarlyArr = true;
      isArr = true;
    } else if (expArr - schArr > timeDifferenceThreshold) {
      isDelayedArr = true;
      isArr = true;
    }

    if (expDep - schDep < -timeDifferenceThreshold) {
      isEarlyDep = true;
      isDep = true;
    } else if (expDep - schDep > timeDifferenceThreshold) {
      isDelayedDep = true;
      isDep = true;
    }
    let parsedExpArr;
    if (expArr instanceof Date && !isNaN(expArr)) {
      if (!isEarlyArr && !isDelayedArr) {
        parsedExpArr = 'RT';
      } else {
        parsedExpArr = parseIndividualTime(expArr);
      }
    } else {
      parsedExpArr = '-';
    }

    let parsedExpDep;
    if (expDep instanceof Date && !isNaN(expDep)) {
      if (!isEarlyDep && !isDelayedDep) {
        parsedExpDep = 'RT';
      } else {
        parsedExpDep = parseIndividualTime(expDep);
      }
    } else {
      parsedExpDep = '-';
    }
    return {
      schArr: parseIndividualTime(schArr),
      expArr: parsedExpArr,
      schDep: parseIndividualTime(schDep),
      expDep: parsedExpDep,
      earArr: isEarlyArr,
      delArr: isDelayedArr,
      earDep: isEarlyDep,
      delDep: isDelayedDep
    };
  }

  function parseIndividualTime(input) {
    const dt = new Date(input);
    const output = dt.toLocaleTimeString([], {
      hour: '2-digit',
      minute: '2-digit'
    });
    if (output !== 'Invalid Date') {
      return output;
    }
    return '-';
  }

  function processNrcc(messages) {
    // Remove newlines and then <p> tags from input and append to array
    let arrMessages;
    if (!Array.isArray(messages)) {
      arrMessages = [messages];
    } else {
      arrMessages = messages;
    }
    let processedMessages = [];
    for (const message of arrMessages) {
      const msgText = message.xhtmlMessage;
      processedMessages.push(msgText.replace(/[\n\r]/g, '').replace(/<\/?p[^>]*>/g, ''));
    }
    return processedMessages;
  }

  onMount(() => {
    fetchData();
  });
</script>

{#if isLoading}
  <Loading />
{:else}
  {#if alerts.length}
    <AlertBar {alerts} />
  {/if}
  <table>
    <tr><td colspan="8" id="timestamp">Updated: {dataAge.toLocaleTimeString()} - Staff Boards under development</td></tr>
    <tr>
      <th class="id">ID</th>
      <th class="from">From</th>
      <th class="to">To</th>
      <th class="plat">Plat</th>
      <th class="time">Sch Arr</th>
      <th class="time">Exp Arr</th>
      <th class="time">Sch Dep</th>
      <th class="time">Exp Dep</th>
    </tr>
    {#each services as service}
      {#await generateServiceData(service)}
        <tr>
          <td colspan="8"> Loading... </td>
        </tr>
      {:then serviceStats}
        <tr class="{serviceStats.isCancelled && 'can-dat'}">
          <td class="id id-data data">{service.trainid}</td>
          <td class="from from-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}">{serviceStats.from}</td>
          <td class="to to-data data {serviceStats.isCancelled && 'can-dat'} {serviceStats.isNonPublic && 'ecs'}">{serviceStats.to}</td>
          <td class="plat plat-data data {serviceStats.platformHidden && 'hidden'}">{serviceStats.platform.number || '-'}</td>
          <td class="time time-data data">{serviceStats.schArr}</td>
          <td class="time time-data data {serviceStats.isArrDelayed && 'late'} {serviceStats.isEarlyArr && 'early'} {serviceStats.isLateArr && 'late'}"
            >{serviceStats.isArrDelayed ? 'LATE' : serviceStats.expArr}</td
          >
          <td class="time time-data data {serviceStats.isCancelled && 'can-dat'}">{serviceStats.schDep}</td>
          <td class="time time-data data {serviceStats.isDepDelayed && 'late'} {serviceStats.isEarlyDep && 'early'} {serviceStats.isLateDep && 'late'}"
            >{serviceStats.isDepDelayed ? 'LATE' : serviceStats.expDep}</td
          >
        </tr>
        <tr class="text-row">
          <td colspan="8" class="text-data">
            {service.operator}
            {#if serviceStats.length} | {serviceStats.length} carriages{/if}
            <br />
            {#if service.isCancelled}
              {#await getReasonCodeData(service.cancelReason)}
                This train has been cancelled
              {:then reasonCode}
                {reasonCode[0].cancReason}
                <br />
              {/await}
            {/if}
            {#if service?.delayReason}
              {#await getReasonCodeData(service.delayReason)}
                This train has been delayed
              {:then reasonCode}
                {reasonCode[0].lateReason}
                <br />
              {/await}
            {/if}
          </td>
        </tr>
      {:catch}
        <tr>
          <td colspan="8">Unable to load service</td>
        </tr>
      {/await}
    {/each}
  </table>
{/if}

<Nav />

<style>
  #timestamp {
    color: var(--second-text-color);
  }

  table {
    color: white;
    font-weight: normal;
    margin: auto;
    margin-top: 0px;
    padding-right: 8px;
  }

  .data {
    font-weight: normal;
  }

  .id-data {
    color: lightgray;
    text-align: left;
  }

  .from-data,
  .to-data {
    color: yellow;
    text-decoration: none;
    text-align: left;
  }

  .text-row {
    margin-top: 0px;
    padding-bottom: 5px;
  }

  .text-data {
    text-align: left;
    color: cyan;
    font-size: smaller;
  }

  .can-dat {
    color: grey;
    text-decoration: line-through;
  }

  .hidden {
    color: grey;
  }

  .ecs {
    opacity: 0.75;
  }

  .can-time {
    animation: pulse-cancel 1.5s linear infinite;
  }

  .early {
    animation: pulse-early 1.5s linear infinite;
  }

  .late {
    animation: pulse-late 1.5s linear infinite;
  }

  @keyframes pulse-late {
    50% {
      color: var(--main-warning-color);
    }
  }

  @keyframes pulse-cancel {
    50% {
      color: var(--main-alert-color);
    }
  }

  @keyframes pulse-early {
    50% {
      color: rgb(136, 164, 255);
    }
  }
</style>
