import { useCallback, useEffect, useMemo, useState, useContext } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Navigate, Outlet, useNavigate } from "react-router-dom";
import LoadingSpinner from "../components/Spinners/LoadingSpinner";
import { formattedDate } from "../lib";
import usersService from "../services/UsersService";
import { commonHeadBanner } from "../store/CommonHeadBanner";
import { recentActivitiesData } from "../store/RecentActivitiesData";
import { updateUserDetails } from "../store/UserDetails";
import { updateJobs } from "../store/jobLists";
import { updateNotifications } from "../store/notifications";
import { updateUserJobList } from "../store/userJobList";
import { updateWalletDetails } from "../store/walletDetails";
import { familyBannersList } from "../store/FamilyBannerList";
import { familyResources } from "../store/FamilyResources";
import {familyWalletRedeemOptList} from '../store/FamilyWalletRedeemOpt'
import { SocketValues } from "../components/Contexts/SocketIOContext";
import DarkModeContext from '../components/Contexts/DarkModeContext'

const AuthRoute = ({ redirectPath = "/login", children }) => {

  let {joinRoom} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET

  // const [nocache, setNoCache] = useState(false) // holds cache/nocache value

  const {nocache, setNoCache} = useContext(DarkModeContext); // Destructures nocache and set nocache from context API

  const apiCall = useMemo(() => new usersService(), []);
  const dispatch = useDispatch();
  const [lastActivityTime, setLastActivityTime] = useState(Date.now());
  const [isLogin, setIsLogin] = useState({ loading: true, status: false });
  const navigate = useNavigate();

  const { jobListTable, marketTableList, walletTable, familyBannersListTable, homeBanners } = useSelector(
    (state) => state.tableReload
  );

  const {
    userDetails: { username, uid, session, account_type, parent_uid },
  } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active

  let loggedIn = username && session && uid ? true : false; // variable to determine if user is logged in
  
  useEffect(() => {
    //Removing Data stored at localStorage after session expires
    const expireSession = () => {
      sessionStorage.clear();
      localStorage.clear();
      navigate("/login", { replace: true }); // redirects user to login page after session expires
    };

    const checkInactivity = setInterval(() => {
      if (account_type === "FAMILY") {
        if (Date.now() - Number(lastActivityTime) > Number(process.env.REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY)) {
          expireSession();
        }
      } else {
        if (Date.now() - Number(lastActivityTime) > Number(process.env.REACT_APP_SESSION_EXPIRE_MINUTES)) {
          expireSession();
        }
      }
    }, process.env.REACT_APP_SESSION_EXPIRE_CHECKER); // Checks for inactivity every minute

    // cleaning up listeners
    return () => {
      clearInterval(checkInactivity);
    };
  }, [lastActivityTime, navigate, isLogin.status]);

  // Reset last activity time on user input
  const resetTime = useCallback(() => {
    setLastActivityTime(Date.now());
  }, []);

  useEffect(() => {
    window.addEventListener("mousemove", resetTime);
    window.addEventListener("keydown", resetTime);

    return () => {
      window.removeEventListener("mousemove", resetTime);
      window.removeEventListener("keydown", resetTime);
    };
  }, [resetTime]);

  useEffect(() => {
    if (!loggedIn) {
      const loadProfile = () => {
        // function to load user profile
        setIsLogin({ loading: true, status: false });
        apiCall
          .loadProfile()
          .then((res) => {
            if (res?.data?.internal_return < 0) {
              setIsLogin({ loading: false, status: false });
              return;
            }
            dispatch(updateUserDetails({ ...res.data }));
            setIsLogin({ loading: false, status: true });
            setNoCache(true) // Sets no cache to true, so as to trigger nocache whenever used in api call
          })
          .catch((error) => {
            setIsLogin({ loading: false, status: false });
          });
      };
      loadProfile();
    }else{
      setIsLogin({ loading: false, status: true });
      setNoCache(true) // Sets no cache to true, so as to trigger nocache whenever used in api call
    }
  }, []);

  //FUNCTION TO GET COMMON HEAD DATA
  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FAMILY'){  // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
      return
    }
      dispatch(commonHeadBanner({loading:true, data:{}}));
      apiCall
        .getHeroJBanners()
        .then((res) => {
          if (res?.data?.internal_return < 0) {
            return;
          }
          dispatch(commonHeadBanner({loading:false, data:res.data}));
        })
        .catch((error) => {
          dispatch(commonHeadBanner({loading:false, data:{}}));
        });
  }, [isLogin.status, homeBanners]);

  useEffect(() => { // FUNCTION TO GET NOTIFICATIONS LIST
    const notifications = () => {
      // function to load user notification
      dispatch(updateNotifications({ loading: true }));
      apiCall
        .getMyNotifications()
        .then((res) => {
          if (res?.data?.internal_return < 0) {
            dispatch(updateNotifications({ loading: false, data: null }));
            return;
          }
          const _raw = res.data?.result_list;

          //Sort the notifications in ascending order based on the API time
          const _sorted = _raw?.sort((a, b) => {
            const timeA = new Date(a?.date)?.getTime();
            const timeB = new Date(b?.date)?.getTime();
            return timeA - timeB;
          });

          // header component
          const _header = _sorted?.slice(0, 5);
          // Notification Layout
          const _today = _sorted?.slice(0, 7);

          const _days = () => {
            const sevenDaysAgo = new Date();
            sevenDaysAgo.setDate(new Date() - 7);
            return _sorted?.filter((notification) => {
              const notificationDate = new Date(
                formattedDate(notification?.date)
              );
              return notificationDate >= sevenDaysAgo;
            });
          };

          // Dispatch all notifications, sorted, and recent based on their filter type
          dispatch(
            updateNotifications({
              loading: false,
              // data: {
              //   raw: _raw,
              //   today: _today,
              //   // days: _days(),
              //   sort: _sorted,
              //   header: _header,
              // },
              data: _sorted,
            })
          );
        })
        .catch((error) => {
          dispatch(updateNotifications({ loading: false, data: null }));
        });
    };
      // delay verify requests by 10000ms
    const delay15secs = setTimeout(notifications, 15000)
    return ()=> clearTimeout(delay15secs)
  }, []);

  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
      return
    }
    const getMyJobList = async () => {
      dispatch(updateUserJobList({ loading: true, data: [] }));
      try {
        const res = await apiCall.getMyJobList();
        // setMyJobList({loading: false, data:res.data})
        // setMyJobList(res.data);
        dispatch(updateUserJobList({ loading: false, data: res?.data }));
      } catch (error) {
        dispatch(updateUserJobList({ loading: false, data: [] }));
        // setMyJobList({loading: false, data:[]})
        // console.log("Error getting mode");
      }
    };
    getMyJobList();
  }, [jobListTable, isLogin.status]);

  //FUNCTION TO GET FULL USER WALLETS
  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
      return
    }
    const getMyWalletList = async () => {
      dispatch(updateWalletDetails({ loading: true, data: [] }));
      try {
        const res = await apiCall.getUserWallets();
        // console.log("wallet - >", res.data);
        dispatch(
          updateWalletDetails({ loading: false, data: res?.data?.result_list })
        );
      } catch (error) {
        dispatch(updateWalletDetails({ loading: false, data: [] }));
        // console.log("Error getting mode");
      }
    };
    getMyWalletList();
  }, [walletTable, isLogin.status]);


  // FUNCTION TO GET MARKET JOB LIST
  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
      return
    }
    // Getting market data
    const getMarketActiveJobList = async () => {
      dispatch(updateJobs({loading: true}));
      try {
        const res = await apiCall.getActiveJobList();
        dispatch(updateJobs({loading: false, ...res.data}));
      } catch (error) {
        dispatch(updateJobs({loading: false}));
        // console.log("Error getting mode");
      }
    };
    getMarketActiveJobList();
  }, [apiCall, dispatch, marketTableList, isLogin.status]);

  //FUNCTION TO GET COMMON HEAD DATA
  // useEffect(() => {
  //   if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
  //     return
  //   }
  //   apiCall
  //     .getRecentActivitiedData()
  //     .then((res) => {
  //       //   debugger;
  //       if (res?.data?.internal_return < 0) {
  //         return;
  //       }
  //       dispatch(recentActivitiesData(res.data));
  //     })
  //     .catch((error) => {
  //       console.log("ERROR ", error);
  //     });
  // }, [isLogin.status]);


  //FUNCTION TO GET FAMILY BANNERS
  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || isLogin.loading || account_type == 'FULL'){  // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FULL
      return
    }
    const getFamilyBanners = async () => { // FUNCTION TO GET FAMILY BANNERS
      // setFamilyBannersList({loading:true, result:[]});
      dispatch(familyBannersList({loading:true}))
      const noCache = (isLogin.status && nocache )? 1 : 0
      const reqData = {nocache: noCache}
      try {
        const res = await apiCall.getFamilyBannersList(reqData);
        dispatch(familyBannersList({...res?.data, loading:false}))
      } catch (error) {
        dispatch(familyBannersList({loading:false}))
        // console.log("Error getting tasks");
      }
    };
    getFamilyBanners()
  }, [isLogin.status, familyBannersListTable]);

  //FUNCTION TO GET FAMILY RESOURCES
  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FULL'){  // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FULL
      return
    }
    const getFamilyResourcesList = async () => { // FUNCTION TO GET FAMILY BANNERS
      try {
        const res = await apiCall.getFamilyResources();
        dispatch(familyResources(res?.data?.result_list))
        // console.log('RESPONSE', res?.data?.result_list)
      } catch (error) {
        // console.log("Error getting tasks");
      }
    };
    getFamilyResourcesList()
  }, [isLogin.status]);


  //FUNCTION TO GET FAMILY WALLET REDEEM OPTIONS
  useEffect(() => {
    if((!loggedIn && !isLogin.status) || isLogin.loading || account_type == 'FULL'){  // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FULL
      return
    }
    const familyWalletRedeemOptions = async () => { // FUNCTION TO GET FAMILY WALLET REDDEM OPTIONS
      dispatch(familyWalletRedeemOptList({loading: true, image: '', data:{}}))
      apiCall.getFamilyWalletRedeemOptions().then((res)=>{
          dispatch(familyWalletRedeemOptList({loading: false, image: res?.data?.session_image_server, data:res?.data?.result_list}))
      }).catch((err)=>{
          // console.log(err)
          dispatch(familyWalletRedeemOptList({loading: false, image: '', data:{}}))
      })
    };
    familyWalletRedeemOptions()
  }, [isLogin.status]);

  useEffect(()=>{ // sends an event to the socket to enable user join a room to be able to receive update when jobs enters the market
      joinRoom('full-markets-jobs')
  },[isLogin.status])

  useEffect(()=>{ // sends an event to the socket to enable user join a room to be able to receive update for parent child job assign
    if(loggedIn || isLogin.status){
      joinRoom(`FAMILY-${account_type == 'FULL' ? uid : sessionStorage.getItem('parent_uid')}`)
      // console.log(`Room joined for parent child task assign as ${account_type} with ${account_type == 'FULL' ? uid : sessionStorage.getItem('parent_uid')}}`)
    }
  },[isLogin.status])

  // RENDER PAGE
  return isLogin.loading && !loggedIn ? (
    <LoadingSpinner size="32" color="sky-blue" height="h-screen" />
  ) : !isLogin.status && !loggedIn ? (
    <Navigate to={redirectPath} replace />
  ) : (
    children || <Outlet />
  );
};

export default AuthRoute;
