/* eslint-disable radix */
import {
  compareAsc,
  formatDistanceStrict,
  intervalToDuration,
  formatDuration,
  differenceInSeconds,
  format,
  fromUnixTime,
} from "date-fns";
import { ipcRenderer } from "electron";
import React, { useEffect, useState } from "react";
import ScannedTicket from "../../models/Application/ScannedTicket";
import ScannedTicketSimple from "../../models/Application/ScannedTicketSimple";
import Tarif from "../../models/Application/Tarif";
import Template from "../../models/Application/Template";
import Log from "../../models/Logs/Log";
import { getRootStore } from "../../models/root-store.ts";

function getRandomInt(min: number, max: number) {
  const mini = Math.ceil(min);
  const maxi = Math.floor(max);
  return Math.floor(Math.random() * (maxi - mini) + mini); // The maximum is exclusive and the minimum is inclusive
}

// Not used for now
const HomeContentBottomExit = () => {
  const [rootStore] = useState(() => getRootStore());
  // const [emvCommandSend, setEmvCommandSend] = useState(false);

  const [state, setState] = React.useState("nothing");
  const [scannedTicket, setScannedTicket] = React.useState<ScannedTicket>();
  const [unlimitedCredits, setUnlimitedCredits] = React.useState(false);
  const [template, setTemplate] = React.useState<Template>();
  const [tarif, setTarif] = React.useState<Tarif>();
  const [startTime, setStartTime] = useState<Date>();
  const [endTime, setEndTime] = useState<Date>();
  const [time, setTime] = useState(format(new Date(), "HH:mm:ss - dd/MM/yyyy"));
  const [timeMomentPay, setTimeMomentPay] = useState(new Date());

  const checkTime = () => {
    let localState = 0;
    if (endTime) {
      localState = compareAsc(timeMomentPay, endTime);
      setState(localState.toString());
      return true;
    }
    return false;
  };

  const checkDistanceWords = () => {
    let localDistance = "";
    if (endTime) {
      localDistance = formatDistanceStrict(timeMomentPay, endTime);
    }
    return localDistance;
  };

  const checkPay = async (endDateTicket: any, tarifScannedTicket: any) => {
    if (typeof endDateTicket === "undefined") return -1;
    if (typeof tarifScannedTicket === "undefined") return -1;
    const endDateScannedTicket = new Date(endDateTicket);
    // The endTime is on location 1 of the array [1]
    let localDistanceSeconds = 0;
    localDistanceSeconds = differenceInSeconds(
      new Date(),
      endDateScannedTicket
    );
    setTime(format(new Date(), "HH:mm:ss - dd/MM/yyyy"));
    setTimeMomentPay(new Date());
    let localPriceToPay;
    if (tarifScannedTicket) {
      localPriceToPay = await tarifScannedTicket.priceToPay(
        localDistanceSeconds
      );
    }
    if (
      typeof localPriceToPay === "number" &&
      localPriceToPay !== -1 &&
      localPriceToPay >= 0
    ) {
      return localPriceToPay;
    }
    return -1;
  };

  // Regular expression to check if string is a valid UUID
  const regexExp =
    /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi;

  const handleDecode = async (result: any, onlineTicketResponse: any) => {
    // Checks

    if (result === null && typeof onlineTicketResponse === "undefined") {
      return 0;
    }
    if (
      typeof onlineTicketResponse === "undefined" &&
      (regexExp.test(rootStore.settings.serialMessage) === true ||
        /^\d+$/.test(rootStore.settings.serialMessage))
    ) {
      ipcRenderer.send("mainWindow->main->workerWindowNetwork-ticketById", [
        rootStore.settings.serialMessage,
      ]);
      return 0;
    }
    if (
      typeof onlineTicketResponse !== "undefined" &&
      typeof result === "string"
    ) {
      if (!onlineTicketResponse?.id) return 0;
      // We set the ticket from response
      const onlineTicket = onlineTicketResponse;
      console.log("Online ticket: ", onlineTicket);
      // Check if we have ever scanned before:
      const onlineTicketInState = rootStore.scannedTicketList.ticketById(
        onlineTicket?.id
      );
      console.log("onlineTicketInState", onlineTicketInState);
      console.log("onlineTicket?.id", onlineTicket?.id);

      // Set local state
      rootStore.ui.setLostTicketMode(false);
      rootStore.ui.setViewDetail(false);
      let localScannedTicket: ScannedTicket;
      // If it didn't exist in the state, create it
      let endTimeOnline = onlineTicket?.created + onlineTicket?.free_time;
      // If the ticket has been validated we add to the time
      if (onlineTicket?.state === 3 || onlineTicket?.state === 4) {
        console.log("ticket is validated");
        endTimeOnline =
          onlineTicket?.last_state_change + onlineTicket?.leave_time;
        onlineTicketInState?.setEndTime(endTimeOnline);
      }
      if (typeof onlineTicketInState === "undefined") {
        localScannedTicket = new ScannedTicket({
          id: onlineTicket?.id, // This is very important here we save the entity with id of online ticket
          idTicket: getRandomInt(1000000000, 4294967295),
          version: -1,
          startType: 0,
          startTime: onlineTicket?.created,
          endType: 1,
          endTime: endTimeOnline,
          credits: 1,
          check: "online ticket",
          qrData: result,
        });
        rootStore.scannedTicketList.add(localScannedTicket);
      } else {
        // It exists, now we need to reuse the object in state
        localScannedTicket = onlineTicketInState;
        rootStore.ui.setCreditsError(true);
        return 1;
      }
      setScannedTicket(localScannedTicket);
      setTarif(rootStore.tarifList.all[0]);

      setStartTime(new Date(fromUnixTime(onlineTicket?.created)));
      setEndTime(new Date(fromUnixTime(endTimeOnline)));
      setState(
        compareAsc(new Date(), new Date(fromUnixTime(endTimeOnline))).toString()
      );

      // Return array with:
      // EndTime
      // Tarif
      // Ticket
      // Ticket credits unlimited
      return [
        fromUnixTime(endTimeOnline),
        rootStore.tarifList.all[0],
        0,
        0,
        false,
      ];
    }

    if (rootStore.scannedTicketList.useSimpleTicket) {
      const searchResult = result.search(
        rootStore.scannedTicketList.prefixSimpleTicket
      );
      if (searchResult !== -1) {
        const dataSimpleTicket: string = result.slice(searchResult);
        // Check if we have ever scanned before:
        const ticketInState =
          rootStore.scannedTicketList.simpleTicketById(dataSimpleTicket);
        // Set local state
        rootStore.ui.setLostTicketMode(false);
        rootStore.ui.setViewDetail(false);
        let localScannedTicketSimple: ScannedTicketSimple;
        // If it didn't exist in the state, create it
        if (typeof ticketInState === "undefined") {
          localScannedTicketSimple = new ScannedTicketSimple({
            data: dataSimpleTicket,
          });
          rootStore.scannedTicketList.addSimple(localScannedTicketSimple);
          return 3;
        }
        // If it already exist it's already been used
        rootStore.ui.setCreditsError(true);
        return 1;
      }
    }

    let dataJSON;
    if (result) {
      try {
        dataJSON = JSON.parse(result);
      } catch (e) {
        console.log(e); // error in the above string (in this case, yes)!
        return 0;
      }
    }
    if (Array.isArray(dataJSON) === false) {
      console.log("3");
      return 0;
    }
    if (
      !dataJSON[0] &&
      !dataJSON[1] &&
      !dataJSON[2] &&
      !dataJSON[3] &&
      !dataJSON[4] &&
      !dataJSON[5] &&
      !dataJSON[6] &&
      !dataJSON[7]
    ) {
      return 0;
    }
    if (
      parseInt(dataJSON[6]) <
        rootStore.scannedTicketList.weightToSubstractCredits &&
      parseInt(dataJSON[6]) !== 0
    ) {
      return 0;
    }

    if (typeof parseInt(dataJSON[3]) !== "number") return 0;
    if (typeof parseInt(dataJSON[5]) !== "number") return 0;
    let unlimCreds = false;
    if (parseInt(dataJSON[6]) === 0) {
      unlimCreds = true;
    }

    // Check if we have ever scanned before:
    const ticketInState = rootStore.scannedTicketList.ticketByTicketId(
      parseInt(dataJSON[0])
    );
    // Set local state
    rootStore.ui.setLostTicketMode(false);
    rootStore.ui.setViewDetail(false);
    let localScannedTicket: ScannedTicket;
    // If it didn't exist in the state, create it
    if (typeof ticketInState === "undefined") {
      localScannedTicket = new ScannedTicket({
        idTicket: parseInt(dataJSON[0]),
        version: parseInt(dataJSON[1]),
        startType: parseInt(dataJSON[2]),
        startTime: parseInt(dataJSON[3]),
        endType: parseInt(dataJSON[4]),
        endTime: parseInt(dataJSON[5]),
        credits: parseInt(dataJSON[6]),
        check: dataJSON[7],
        qrData: dataJSON.toString(),
      });
      rootStore.scannedTicketList.add(localScannedTicket);
    } else {
      // It exists, now we need to reuse the object in state
      localScannedTicket = ticketInState;
      // And check if it still has enough credits for at least one passage
      if (
        localScannedTicket.credits <
          rootStore.scannedTicketList.weightToSubstractCredits &&
        parseInt(dataJSON[6]) !== 0
      ) {
        // If it doesn't have enough we return and discard the ticket for this we use number 1 to return
        rootStore.ui.setCreditsError(true);
        return 1;
      }
    }
    if (parseInt(dataJSON[6]) !== 0) {
      rootStore.ui.setCreditsOnTicket(parseInt(dataJSON[6]));
    }
    console.log("localScannedTicket.credits", localScannedTicket.credits);
    setScannedTicket(localScannedTicket);
    const localTemplateId =
      rootStore.templateList.returnTemplateForTicket(localScannedTicket);
    const localTemplate: Template | undefined =
      rootStore.templateList.getTemplateById(localTemplateId);
    if (typeof localTemplate === "undefined") return 0;
    setTemplate(localTemplate);
    setTarif(rootStore.tarifList.getTarifById(localTemplate.idTarif));

    setStartTime(new Date(fromUnixTime(parseInt(dataJSON[3]))));
    setEndTime(new Date(fromUnixTime(parseInt(dataJSON[5]))));
    setState(
      compareAsc(
        new Date(),
        new Date(fromUnixTime(parseInt(dataJSON[5])))
      ).toString()
    );

    // Return array with:
    // EndTime
    // Tarif
    // Ticket
    // Ticket id
    return [
      fromUnixTime(parseInt(dataJSON[5])),
      rootStore.tarifList.getTarifById(localTemplate.idTarif),
      localScannedTicket,
      localScannedTicket.idTicket,
      unlimCreds,
    ];
  };

  // Below is the main useEffect, it will listen to any changes on the serial
  useEffect(() => {
    let fetchedOnlineInfo: any;

    async function decodeAndGetPay() {
      // Below will return 0 for decoding error, 1 for not enough credits from existing scanned ticket,
      // Below will return 0 for decoding error, 1 for not enough credits from existing scanned ticket,
      // 3 is a simple ticket
      //
      if (
        rootStore.settings.serialMessage === "" &&
        typeof fetchedOnlineInfo === "undefined"
      )
        return;

      const returnFromDecode = await handleDecode(
        rootStore.settings.serialMessage,
        fetchedOnlineInfo
      );
      // Reset the fetchedData
      fetchedOnlineInfo = undefined;
      // If we get 3 we have a good simpleTicket scanned
      if (returnFromDecode === 3) {
        // We change the amount of credits on the ticket
        /*
        scannedTicketLocally?.setCredits(
          scannedTicketLocally?.credits -
            rootStore.scannedTicketList.weightToSubstractCredits
        );
        */
        ipcRenderer.postMessage(
          "mainWindow->main->workerWindowNetwork-openPassage",
          rootStore.passageList.defaultPassageId,
          []
        );
        rootStore.ui.setEmvPaymentNotNeccessary(true);
        rootStore.ui.setPriceToPay(-1);
        setTimeout(() => {
          rootStore.ui.setEmvPaymentNotNeccessary(false);
        }, 10000);
        return;
      }

      if (returnFromDecode !== 0 && returnFromDecode !== 1) {
        const localPriceToPay = await checkPay(
          returnFromDecode[0],
          returnFromDecode[1]
        );
        const tarifLocal = returnFromDecode[1];
        const scannedTicketLocally: any = returnFromDecode[2];
        if (typeof localPriceToPay === "number" && localPriceToPay >= 0) {
          rootStore.ui.setPriceToPay(-1);
        }
        if (localPriceToPay === 0) {
          // We change the amount of credits on the ticket
          if (returnFromDecode[4] === false && returnFromDecode[3] !== 0) {
            scannedTicketLocally?.setCredits(
              scannedTicketLocally?.credits -
                rootStore.scannedTicketList.weightToSubstractCredits
            );
          }
          ipcRenderer.postMessage(
            "mainWindow->main->workerWindowNetwork-openPassage",
            rootStore.passageList.defaultPassageId,
            []
          );
          rootStore.ui.setEmvPaymentNotNeccessary(true);
          rootStore.ui.setPriceToPay(-1);
          setTimeout(() => {
            rootStore.ui.setEmvPaymentNotNeccessary(false);
          }, 10000);
          return;
        }
        rootStore.ui.setPriceToPay(localPriceToPay || -1);
        checkTime();
        checkDistanceWords();
        const scannedTktId = returnFromDecode[3];
        // Here we set the amount to pay
        /*
        if (typeof localPriceToPay !== "undefined") {
        }
        */
      }
    }

    decodeAndGetPay();
    rootStore.settings.setSerialMessage("");

    ipcRenderer.on(
      "mainWindow->workerWindowNetwork-ticketById-reply",
      async (event, fetchedData) => {
        console.log("received ipc ", fetchedData);
        if (!fetchedData?.id) {
          rootStore.ui.setCreditsError(true);
          setTimeout(() => rootStore.ui.setCreditsError(false), 3000);
          return;
        }
        fetchedOnlineInfo = fetchedData;
        await decodeAndGetPay();
      }
    );

    return () => {
      ipcRenderer.removeAllListeners(
        "mainWindow->workerWindowNetwork-ticketById-reply"
      );
    };
  }, [rootStore.settings.serialMessage]);

  // Below to reset screen after message that ticket was already used because credits are done
  useEffect(() => {
    let timer: ReturnType<typeof setTimeout>;
    if (rootStore.ui.creditsError === true) {
      rootStore.ui.setCreditsError(true);
      timer = setTimeout(() => {
        rootStore.ui.setCreditsError(false);
      }, 3000);
    }
    return () => {
      clearTimeout(timer);
    };
  }, [rootStore.ui.creditsError]);

  return <></>;
};

export default HomeContentBottomExit;
