'use client';

import { signOut, useSession } from 'next-auth/react';
import { usePathname, useRouter } from 'next/navigation';
import { useEffect, useEffectEvent, useRef } from 'react';
import { toast } from 'sonner';

const IDLE_TIMEOUT_MS = 5 * 60 * 1000;
const TIMER_BUFFER_MS = 500;
const ACTIVITY_SYNC_THROTTLE_MS = 1000;
const LAST_ACTIVITY_STORAGE_KEY = 'training-system:last-activity-at';
const IDLE_SIGN_OUT_STORAGE_KEY = 'training-system:idle-sign-out-at';
const AUTH_ROUTE_PREFIX = '/auth';

function readTimestamp(key: string) {
  if (typeof window === 'undefined') {
    return null;
  }

  const rawValue = window.localStorage.getItem(key);

  if (!rawValue) {
    return null;
  }

  const value = Number(rawValue);

  return Number.isFinite(value) ? value : null;
}

function writeTimestamp(key: string, value: number) {
  window.localStorage.setItem(key, String(value));
}

export function SessionInactivityGuard() {
  const router = useRouter();
  const pathname = usePathname();
  const { status } = useSession();

  const timeoutRef = useRef<number | null>(null);
  const lastActivityRef = useRef<number>(0);
  const lastSyncedActivityRef = useRef<number>(0);
  const isSigningOutRef = useRef(false);

  const clearIdleTimeout = useEffectEvent(() => {
    if (timeoutRef.current !== null) {
      window.clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }
  });

  const performIdleSignOut = useEffectEvent(async () => {
    if (isSigningOutRef.current) {
      return;
    }

    isSigningOutRef.current = true;
    clearIdleTimeout();

    const signedOutAt = Date.now();
    writeTimestamp(IDLE_SIGN_OUT_STORAGE_KEY, signedOutAt);
    window.localStorage.removeItem(LAST_ACTIVITY_STORAGE_KEY);

    toast.error('เซสชันหมดอายุเนื่องจากไม่มีการใช้งานเกิน 5 นาที');

    try {
      await signOut({ redirect: false });
    } finally {
      router.replace('/auth/sign-in?reason=session-expired');
      router.refresh();
    }
  });

  const scheduleIdleTimeout = useEffectEvent((lastActivityAt: number) => {
    clearIdleTimeout();

    const remainingMs = IDLE_TIMEOUT_MS - (Date.now() - lastActivityAt);

    if (remainingMs <= 0) {
      void performIdleSignOut();
      return;
    }

    timeoutRef.current = window.setTimeout(() => {
      void performIdleSignOut();
    }, remainingMs + TIMER_BUFFER_MS);
  });

  const syncActivity = useEffectEvent((timestamp: number, shouldBroadcast: boolean) => {
    lastActivityRef.current = timestamp;
    scheduleIdleTimeout(timestamp);

    if (!shouldBroadcast) {
      return;
    }

    if (timestamp - lastSyncedActivityRef.current < ACTIVITY_SYNC_THROTTLE_MS) {
      return;
    }

    lastSyncedActivityRef.current = timestamp;
    writeTimestamp(LAST_ACTIVITY_STORAGE_KEY, timestamp);
  });

  useEffect(() => {
    if (status !== 'authenticated' || pathname?.startsWith(AUTH_ROUTE_PREFIX)) {
      clearIdleTimeout();
      isSigningOutRef.current = false;
      return;
    }

    const now = Date.now();
    const storedLastActivity = readTimestamp(LAST_ACTIVITY_STORAGE_KEY);
    const initialLastActivity = storedLastActivity ?? now;

    syncActivity(initialLastActivity, !storedLastActivity);

    const handleUserActivity = () => {
      syncActivity(Date.now(), true);
    };

    const handleStorage = (event: StorageEvent) => {
      if (event.key === LAST_ACTIVITY_STORAGE_KEY && event.newValue) {
        const nextTimestamp = Number(event.newValue);

        if (Number.isFinite(nextTimestamp) && nextTimestamp > lastActivityRef.current) {
          syncActivity(nextTimestamp, false);
        }

        return;
      }

      if (
        event.key === IDLE_SIGN_OUT_STORAGE_KEY &&
        event.newValue &&
        !isSigningOutRef.current
      ) {
        void performIdleSignOut();
      }
    };

    const handleVisibilityChange = () => {
      if (document.visibilityState === 'visible') {
        const sharedTimestamp = readTimestamp(LAST_ACTIVITY_STORAGE_KEY) ?? Date.now();
        syncActivity(sharedTimestamp, false);
      }
    };

    const events: Array<keyof WindowEventMap> = [
      'focus',
      'keydown',
      'mousedown',
      'scroll',
      'touchstart'
    ];

    for (const eventName of events) {
      window.addEventListener(eventName, handleUserActivity, { passive: true });
    }

    window.addEventListener('storage', handleStorage);
    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      clearIdleTimeout();

      for (const eventName of events) {
        window.removeEventListener(eventName, handleUserActivity);
      }

      window.removeEventListener('storage', handleStorage);
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [pathname, status]);

  return null;
}
