import { useEffect, useRef } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { useDispatch } from 'react-redux';
import { clearFcmToken } from 'store/reducers/fcmSlice';
import { logoutUser } from 'store/reducers/loginUserSlice';
import {
  ABSOLUTE_SESSION_TIMEOUT_MS,
  ACTIVITY_STORAGE_KEY,
  AUTH_PRESENCE_KEY,
  INACTIVITY_TIMEOUT_MS,
  SESSION_START_STORAGE_KEY,
  isSessionActive,
  markActivity,
  markSessionStart,
  performSessionLogout
} from 'utils/session';

const ACTIVITY_EVENTS = ['mousemove', 'mousedown', 'keydown', 'scroll', 'touchstart', 'wheel'];
const ACTIVITY_WRITE_THROTTLE_MS = 5000;
const IDLE_CHECK_INTERVAL_MS = 15000;

// Two independent timers, both enforced from localStorage so every tab on the
// origin agrees:
//  - INACTIVITY_TIMEOUT_MS: logs out after 1 hour with no interaction, so
//    a laptop left unlocked doesn't leave the console open indefinitely.
//  - ABSOLUTE_SESSION_TIMEOUT_MS: a hard 1-hour cap since login, even if
//    the user has been continuously active, so localStorage (auth keys, FCM
//    token, cached zone list) never lingers on disk longer than that.
// A logout in one tab (auth key cleared) is picked up by the others via the
// 'storage' event.
const useInactivityLogout = () => {
  const queryClient = useQueryClient();
  const dispatch = useDispatch();
  const lastWriteRef = useRef(0);

  useEffect(() => {
    const doLogout = () => performSessionLogout({ queryClient, dispatch, clearFcmToken, logoutUser });

    const handleActivity = () => {
      const now = Date.now();
      if (now - lastWriteRef.current < ACTIVITY_WRITE_THROTTLE_MS) return;
      lastWriteRef.current = now;
      markActivity();
    };

    const handleStorage = (event) => {
      if (event.key === AUTH_PRESENCE_KEY && !event.newValue) {
        doLogout();
      }
    };

    // Guards against the browser restoring a cached (bfcache) copy of a
    // protected page via the back/forward button after logout happened.
    const handlePageShow = (event) => {
      if (event.persisted && !isSessionActive()) {
        window.location.replace('/login');
      }
    };

    if (isSessionActive()) {
      if (!localStorage.getItem(ACTIVITY_STORAGE_KEY)) markActivity();
      // Sessions that were already open before this feature shipped won't have
      // a start time yet — give them a fresh 1-hour window instead of
      // treating them as already expired.
      if (!localStorage.getItem(SESSION_START_STORAGE_KEY)) markSessionStart();
    }

    ACTIVITY_EVENTS.forEach((eventName) => window.addEventListener(eventName, handleActivity, { passive: true }));
    window.addEventListener('storage', handleStorage);
    window.addEventListener('pageshow', handlePageShow);

    const intervalId = setInterval(() => {
      if (!isSessionActive()) return;

      const lastActivity = Number(localStorage.getItem(ACTIVITY_STORAGE_KEY)) || Date.now();
      if (Date.now() - lastActivity >= INACTIVITY_TIMEOUT_MS) {
        doLogout();
        return;
      }

      const sessionStart = Number(localStorage.getItem(SESSION_START_STORAGE_KEY)) || Date.now();
      if (Date.now() - sessionStart >= ABSOLUTE_SESSION_TIMEOUT_MS) {
        doLogout();
      }
    }, IDLE_CHECK_INTERVAL_MS);

    return () => {
      ACTIVITY_EVENTS.forEach((eventName) => window.removeEventListener(eventName, handleActivity));
      window.removeEventListener('storage', handleStorage);
      window.removeEventListener('pageshow', handlePageShow);
      clearInterval(intervalId);
    };
  }, [queryClient, dispatch]);
};

export default useInactivityLogout;
