import React, { useContext, useState } from "react";

import api from "../../services/vehiclesAPI";
import { LocalDateTimeString } from "../../utils/dates";
import { useInterval } from "usehooks-ts";

const CANSignalContext = React.createContext();

const BlankSignal = (msg) => ({
  timestamp: "",
  signal: msg,
  value: "",
});

const transformSignals = (signals) =>
  signals
    .map((signal) => {
      const { timestamp, value, name } = signal;

      return {
        timestamp: LocalDateTimeString(timestamp),
        signal: name,
        value: value,
      };
    })
    .flat();

export const CANSignalProvider = ({ token, children }) => {
  // auto scale polling if not getting response
  const delays = [500, 1500, 3000, 6000];
  const [delayIndex, setDelayIndex] = useState(2);
  const [vin, setVIN] = useState(null);
  const [signals, setSignals] = useState([]);
  const [utc, setUtc] = useState(undefined);
  const [hasFoundSignalsBefore, setHasFoundSignalsBefore] = useState(false);

  useInterval(
    () => {
      getCANSignals()
    }, vin ? delays[delayIndex] : null
  );

  const getCANSignals = async () => {
    try {
      if (!vin) return;

      const result = await api.getCANSignals(vin, {
        after_utc: utc,
      }, token);

      if (result.error) {
        throw new Error(`Get CAN signals error. ${result.message}`);
      }

      const mostRecentTimestamp = result.data?.[0]?.timestamp;
      if (mostRecentTimestamp) {
        setUtc(new Date(mostRecentTimestamp).getTime() - 50); // apply slight offset to ensure last CAN Signals sent before sleep are returned.
      } else {
        setUtc(undefined);
      }

      const items = transformSignals(result.data);

      if (items.length > 0) {
        setSignals(items);
        setHasFoundSignalsBefore(true)
      } else if (!hasFoundSignalsBefore) {
        setSignals([BlankSignal("No signals")]);
      }
    } catch (e) {
      setSignals([BlankSignal(e.message)]);
    }
  };

  return (
    <CANSignalContext.Provider
      value={{
        queryDate: utc && new Date(utc).toLocaleTimeString(),
        signals,
        setVIN,
        delays,
        delayIndex,
        setDelayIndex,
      }}
    >
      {children}
    </CANSignalContext.Provider>
  );
};

export const useCANSignalContext = () => useContext(CANSignalContext);
