import React, { useState, useEffect, useRef } from "react";
import "./App.css";
import "./components/Loading.css";
import {
  BrowserRouter as Router,
  Route,
  Routes,
  useNavigate,
  useLocation,
} from "react-router-dom";
import socket from "./services/socketService";

import API_BASE_URL from "./config.js";

import Dashboard from "./pages/Dashboard";
import ScanMeja from "./pages/ScanMeja";
import CafePage from "./pages/CafePage";
import SearchResult from "./pages/SearchResult";
import Cart from "./pages/Cart";
import Invoice from "./pages/Invoice";
import Transactions from "./pages/Transactions";
import Footer from "./components/Footer";

import GuestSideLogin from "./pages/GuestSideLogin";
import GuestSide from "./pages/GuestSide";
import { getItemTypesWithItems } from "./helpers/itemHelper.js";
import { getTableByCode } from "./helpers/tableHelper.js";

import {
  getTransactionsFromCafe,
} from "./helpers/transactionHelpers";
import {
  getConnectedGuestSides,
  getClerks,
  removeConnectedGuestSides,
} from "./helpers/userHelpers.js";
import {
  getLocalStorage,
  removeLocalStorage,
} from "./helpers/localStorageHelpers";
import { calculateTotals } from "./helpers/cartHelpers";
import {
  subscribeUser,
  resetNotificationSubscription,
} from "./helpers/subscribeHelpers.js";
import Modal from "./components/Modal"; // Import your modal component

function App() {
  const location = useLocation();
  const navigate = useNavigate();
  const [user, setUser] = useState([]);
  const [shopClerks, setShopClerks] = useState([]);
  const [guestSideOfClerk, setGuestSideOfClerk] = useState(null);
  const [guestSides, setGuestSides] = useState([]);
  const [shopId, setShopId] = useState("");
  const [table, setTable] = useState([]);
  const [totalItemsCount, setTotalItemsCount] = useState(0);
  const [deviceType, setDeviceType] = useState("");
  const [shop, setShop] = useState([]);
  const [shopItems, setShopItems] = useState([]);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [modalContent, setModalContent] = useState(null);
  const transactionList = useRef(null);
  const [queue, setQueue] = useState([]);


  const validTransactionStates = [
    'new_transaction',
    'transaction_canceled',
    'transaction_pending',
    'transaction_confirmed',
    'payment_claimed',
    'transaction_success',
    'transaction_end',
    'transaction_failed',
  ];

  useEffect(() => {
    const calculateTotalsFromLocalStorage = () => {
      const { totalCount } = calculateTotals(shopId);
      setTotalItemsCount(totalCount);
    };

    calculateTotalsFromLocalStorage();

    const handleStorageChange = () => {
      calculateTotalsFromLocalStorage();
    };

    window.addEventListener("localStorageUpdated", handleStorageChange);

    return () => {
      window.removeEventListener("localStorageUpdated", handleStorageChange);
    };
  }, [shopId]);

  const handleSetParam = async ({ shopId, tableCode }) => {
    setShopId(shopId);

    if (tableCode)
      if (table.length == 0) {
        const gettable = await getTableByCode(shopId, tableCode);
        if (gettable) setTable(gettable);
      }
  };

  useEffect(() => {
    const fetchData = async () => {
      console.log("gettingItems");
      try {
        const { response, cafe, data } = await getItemTypesWithItems(shopId);
        if (response.status === 200) {
          setShop(cafe);
          setShopItems(data);
          console.log(data)
          // Filter out unavailable items
          const filteredData = data
            .map((itemType) => ({
              ...itemType,
              itemList: itemType.itemList.filter((item) => item.availability),
            }))
            .filter((itemType) => itemType.itemList.length > 0); // Remove empty itemTypes

          // Update local storage by removing unavailable items
          const updatedLocalStorage =
            JSON.parse(localStorage.getItem("cart")) || [];
          const newLocalStorage = updatedLocalStorage.map((cafe) => {
            if (cafe.cafeId === shopId) {
              return {
                ...cafe,
                items: cafe.items.filter((item) =>
                  filteredData.some((filtered) =>
                    filtered.itemList.some(
                      (i) => i.itemId === item.itemId && i.availability
                    )
                  )
                ),
              };
            }
            return cafe;
          });
          localStorage.setItem("cart", JSON.stringify(newLocalStorage));

          socket.on("transaction_created", () => {
            console.log("transaction created");
          });
        }
      } catch (error) {
        console.error("Error fetching shop items:", error);
      }
    };

    if (shopId !== "") fetchData();
  }, [shopId]);

  const rmConnectedGuestSides = async (gueseSideSessionId) => {
    const sessionLeft = await removeConnectedGuestSides(gueseSideSessionId);
    setGuestSides(sessionLeft.guestSideList);
  };

  useEffect(() => {
    if (socket == null) return;

    if (getLocalStorage("authGuestSide")) {
      socket.emit("checkGuestSideToken", {
        token: getLocalStorage("authGuestSide"),
      });
    } else {
      socket.emit("checkUserToken", {
        token: getLocalStorage("auth"),
        shopId,
      });
    }

    //for guest
    socket.on("transaction_pending", async (data) => {
      console.log("transaction notification");
      // Call `setModal` with content and parameters
      setModal("transaction_pending", data);
    });

    socket.on("transaction_confirmed", async (data) => {
      console.log("transaction notification" + data);
      setModal("transaction_confirmed", data);
    });

    socket.on("transaction_success", async (data) => {
      console.log("transaction notification");
      setModal("transaction_success", data);
    });

    socket.on("transaction_end", async (data) => {
      console.log("transaction notification");
      setModal("transaction_end", data);
    });

    socket.on("payment_claimed", async (data) => {
      console.log(data);
      setModal("payment_claimed", data);
    });

    socket.on("transaction_failed", async (data) => {
      console.log("transaction notification");
      setModal("transaction_failed", data);
    });


    const checkNotifications = () => {
      let permission = Notification.permission;

      // Check current permission
      const searchParams = new URLSearchParams(location.search);
      let searchModal = searchParams.get("modal") || ''; // Get transactionId or set it to empty string

      if (permission !== "granted" && searchModal == '') {
        setModal("req_notification");
      }
    };

    socket.on("checkUserTokenRes", async (data) => {
      if (data.status !== 200) {
        removeLocalStorage("auth");
        setDeviceType("guestDevice");
      } else {
        console.log(data)
        setUser(data.data.user);
        if (
          data.data.user.password == "unsetunsetunset" &&
          localStorage.getItem("settings")
        )
          setModal("complete_account");
        if (data.data.user.cafeId == shopId || data.data.isTheOwner) {
          const connectedGuestSides = await getConnectedGuestSides();
          setGuestSides(connectedGuestSides.sessionDatas);
          console.log("getting guest side");
          setDeviceType("clerk");

          checkNotifications();
        } else {
          setDeviceType("guestDevice");
        }
        if (data.data.user.roleId == 1 && user.userId == shop.ownerId) {
          // shopClerks is can only be obtained by the shop owner
          // so every user that is admin will try to getting shopClerks, even not yet proven that this is their shop
          const shopClerks = await getClerks(shopId);
          if (shopClerks != null) setShopClerks(shopClerks);
        }
      }
    });

    socket.on("checkGuestSideTokenRes", (data) => {
      if (data.status !== 200) {
        removeLocalStorage("authGuestSide");
        navigate("/guest-side");
      } else {
        setGuestSideOfClerk({
          clerkId: data.sessionData.clerkId,
          clerkUsername: data.sessionData.clerkUsername,
        });
        setDeviceType("guestSide");
      }
    });

    socket.on("signout-guest-session", () => {
      navigate("/guest-side");
    });

    socket.on("updateQueue", (response) => {
      setQueue(response); // Only set the queue if it's a valid non-empty array
      console.log("Updated Queue:", response); // Log the valid queue

    });

    return () => {
      socket.off("signout-guest-session");
    };
  }, [socket, shopId]);

  async function checkIfStillViewingOtherTransaction() {

    console.log("transaction notification");
    console.log(modalContent);

    let response;
    response = await getTransactionsFromCafe(shopId, 0, true);
    transactionList.current = response;
    console.log(response);

    // Get current URL's search parameters inside the socket event handler
    const searchParams = new URLSearchParams(location.search);
    let transaction_info = searchParams.get("transactionId") || ''; // Get transactionId or set it to empty string
    console.log(transaction_info);  // Log the updated transaction_info

    // If transaction_info is an empty string, set the modal
    if (transaction_info == '') return false;
    else return true;
  }

  useEffect(() => {
    // This will ensure that searchParams and transaction_info get updated on each render
    socket.on("transaction_created", async (data) => {
      console.log("transaction notification");
      const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction();
      // If transaction_info is an empty string, set the modal
      if (!isViewingOtherTransaction) {
        setModal("new_transaction", data);
      }

      // Show browser notification
      let permission = Notification.permission;
      if (permission !== "granted") return;
      navigator.serviceWorker.ready.then((registration) => {
        registration.showNotification("New Transaction", {
          body: `A new transaction was created: ${data.transactionDetails}`,
          icon: "icon.png", // Optional icon
        });
      });
    });

    socket.on("transaction_canceled", async (data) => {
      console.log("transaction notification");

      const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction();
      // If transaction_info is an empty string, set the modal
      if (!isViewingOtherTransaction) {
        setModal("new_transaction", data);
      }
    });

    // Clean up the socket event listener on unmount or when dependencies change
    return () => {
      socket.off("transaction_created");
      socket.off("transaction_canceled");
    };
  }, [socket, shopId, location]);  // Ensure location is in the dependencies to respond to changes in the URL

  useEffect(() => {
    if (user.cafeId != null && user.cafeId !== shopId) {
      // Preserve existing query parameters
      const currentParams = new URLSearchParams(location.search).toString();

      // Navigate to the new cafeId while keeping existing params
      navigate(`/${user.cafeId}?${currentParams}`, { replace: true });
    }

  }, [user, shopId]);

  function handleMoveToTransaction(direction, from) {
    console.log(direction);
    console.log(from);

    // Find the current index based on the 'from' transactionId
    const currentIndex = transactionList.current.findIndex(item => item.transactionId == from);

    // Determine the new transactionId based on the direction
    let newTransactionId;
    if (direction === 'next') {
      // If we're not at the last transaction, get the next transactionId
      newTransactionId = currentIndex < transactionList.current.length - 1
        ? transactionList.current[currentIndex + 1].transactionId
        : from; // If already at the end, stay on the current transactionId
    } else if (direction === 'previous') {
      // If we're not at the first transaction, get the previous transactionId
      newTransactionId = currentIndex > 0
        ? transactionList.current[currentIndex - 1].transactionId
        : from; // If already at the beginning, stay on the current transactionId
    }

    // Log the new transactionId
    console.log('New Transaction ID:', newTransactionId);

    // Update the URL with the new transactionId using navigate
    navigate(`?transactionId=${newTransactionId}`, { replace: true });

    // Optionally, update state or perform further actions based on the new transactionId
    // Example:
    // setModalContent({ cafeId: shopId, transactionId: newTransactionId });
  }


  const handleModalFromURL = () => {
    const queryParams = new URLSearchParams(location.search);
    const modal = queryParams.get("modal");
    if (modal) setModal(modal);
  };

  useEffect(() => {
    handleModalFromURL();
  }, [shopId]);

  useEffect(() => {
    console.log(shopId + table?.tableCode);
  }, [navigate]);

  // Function to open the modal
  const setModal = (content, params = {}) => {
    const queryParams = new URLSearchParams(location.search);

    // Update the modal and any additional params
    queryParams.set("modal", content);
    Object.entries(params).forEach(([key, value]) => {
      queryParams.set(key, value);
    });

    // Update URL with new parameters
    navigate(`?${queryParams.toString()}`, { replace: true });

    // Prevent scrolling when modal is open
    document.body.style.overflow = "hidden";

    setIsModalOpen(true);
    setModalContent(content)
  };

  // Function to close the modal
  const closeModal = (closeTheseContent = []) => {
    if (
      Array.isArray(closeTheseContent) &&
      (closeTheseContent.length === 0 ||
        closeTheseContent.includes(modalContent))
    ) {
      setIsModalOpen(false);
      setModalContent(null);
      document.body.style.overflow = "auto";

      const queryParams = new URLSearchParams(location.search);

      // Remove the 'modal' parameter
      queryParams.delete("modal");
      queryParams.delete("transactionId");

      // Update the URL without the 'modal' parameter
      navigate({ search: queryParams.toString() }, { replace: true });
    }
  };

  // useEffect(() => {
  //   const askNotificationPermission = async () => {
  //     let permission = Notification.permission;

  //     // Check current permission
  //     if (permission === "default") {
  //       setModal("req_notification");

  //       // Request permission and wait for the result
  //       permission = await Notification.requestPermission();
  //     }

  //     // Handle permission results
  //     if (permission === "granted") {
  //       await resetNotificationSubscription();
  //       closeModal(["req_notification", "denied_notification"]);
  //     } else if (permission === "denied") {
  //       setModal("blocked_notification");
  //       console.error("Notification permission denied.");
  //     }
  //   };

  //   const handleTransactionConfirmed = async (data) => {
  //     console.log("transaction notification", data);
  //     await askNotificationPermission();
  //     setModal("transaction_success", data);
  //   };

  //   // Add socket listener for transaction confirmations
  //   socket.on("transaction_success", handleTransactionConfirmed);

  //   // Cleanup the socket listener on component unmount
  //   return () => {
  //     socket.off("transaction_success", handleTransactionConfirmed);
  //   };
  // }, [user]);

  useEffect(() => {
    const startPermissionPolling = async () => {
      const checkInterval = 5000; // Check every 5 seconds

      const intervalId = setInterval(async () => {
        const permission = Notification.permission;

        if (permission === "granted") {
          await resetNotificationSubscription();
          clearInterval(intervalId); // Stop checking once subscribed
        } else if (permission === "denied") {
          console.error("Notification permission denied.");
        }
      }, checkInterval);
    };

    startPermissionPolling();
  }, []);

  useEffect(() => {
    if ("serviceWorker" in navigator) {
      navigator.serviceWorker.register("/service-worker.js")
        .then(registration => {
          console.log("Service Worker registered with scope:", registration.scope);
        })
        .catch(error => {
          console.error("Service Worker registration failed:", error);
        });
    }
  }, []);

  return (
    <div className="App">
      <header className="App-header" id="header">
        <Routes>
          <Route
            path="/"
            element={
              <Dashboard user={user} socket={socket} setModal={setModal} />
            }
          />
          <Route
            path="/scan"
            element={
              <>
                <ScanMeja
                  sendParam={handleSetParam}
                  shopName={shop.name}
                  shopOwnerId={shop.ownerId}
                  shopItems={shopItems}
                  shopClerks={shopClerks}
                  socket={socket}
                  user={user}
                  guestSides={guestSides}
                  guestSideOfClerk={guestSideOfClerk}
                  removeConnectedGuestSides={rmConnectedGuestSides}
                  setModal={setModal} // Pass the function to open modal
                />
              </>
            }
          />
          <Route
            path="/:shopId/:tableCode?"
            element={
              <>
                <CafePage
                  table={table}
                  sendParam={handleSetParam}
                  welcomePageConfig={shop.welcomePageConfig || false}
                  shopName={shop.name}
                  shopOwnerId={shop.ownerId}
                  shopItems={shopItems}
                  setShopItems={setShopItems}
                  shopClerks={shopClerks}
                  socket={socket}
                  user={user}
                  guestSides={guestSides}
                  guestSideOfClerk={guestSideOfClerk}
                  removeConnectedGuestSides={rmConnectedGuestSides}
                  setModal={setModal} // Pass the function to open modal
                  loading={shop.name == null}
                  queue={queue}
                />
                <Footer
                  showTable={true}
                  shopId={shopId}
                  table={table}
                  cartItemsLength={totalItemsCount}
                  selectedPage={0}
                />
              </>
            }
          />
          <Route
            path="/:shopId/:tableCode?/search"
            element={
              <>
                <SearchResult
                  cafeId={shopId}
                  sendParam={handleSetParam}
                  user={user}
                  shopItems={shopItems}
                  guestSides={guestSides}
                  guestSideOfClerk={guestSideOfClerk}
                  removeConnectedGuestSides={rmConnectedGuestSides}
                  setModal={setModal} // Pass the function to open modal
                />
                <Footer
                  shopId={shopId}
                  table={table}
                  cartItemsLength={totalItemsCount}
                  selectedPage={1}
                />
              </>
            }
          />
          <Route
            path="/:shopId/:tableCode?/cart"
            element={
              <>
                <Cart
                  table={table}
                  sendParam={handleSetParam}
                  socket={socket}
                  totalItemsCount={totalItemsCount}
                  deviceType={deviceType}
                />
                <Footer
                  shopId={shopId}
                  table={table}
                  cartItemsLength={totalItemsCount}
                  selectedPage={2}
                />
              </>
            }
          />
          <Route
            path="/:shopId/:tableCode?/invoice"
            element={
              <>
                <Invoice
                  table={table}
                  sendParam={handleSetParam}
                  socket={socket}
                  deviceType={deviceType}
                />
                <Footer
                  shopId={shopId}
                  table={table}
                  cartItemsLength={totalItemsCount}
                  selectedPage={2}
                />
              </>
            }
          />
          <Route
            path="/:shopId/:tableCode?/transactions"
            element={
              <>
                <Transactions
                  sendParam={handleSetParam}
                  deviceType={deviceType}
                />
                <Footer
                  shopId={shopId}
                  table={table}
                  cartItemsLength={totalItemsCount}
                  selectedPage={3}
                />
              </>
            }
          />
          <Route
            path="/:shopId/guest-side-login"
            element={<GuestSideLogin shopId={shopId} socket={socket} />}
          />
          <Route path="/guest-side" element={<GuestSide socket={socket} />} />
        </Routes>
      </header>
      <Modal
        user={user}
        shop={shop}
        isOpen={isModalOpen}
        modalContent={modalContent}
        handleMoveToTransaction={handleMoveToTransaction}
        welcomePageConfig={shop.welcomePageConfig}
        onClose={closeModal}
        setModal={setModal}
      />
    </div>
  );
}

const AppWrapper = () => (
  <Router>
    <App />
  </Router>
);

export default AppWrapper;
