/**
 * 메뉴 폴링 훅
 *
 * 일정 간격으로 메뉴 변경사항을 확인하고 자동 갱신합니다.
 * 401 응답이 3회 연속 발생하면 세션 만료로 판단하고 폴링을 중지합니다.
 * 토큰 갱신 시 자동으로 폴링을 재시작합니다.
 *
 * @see claudedocs/architecture/[PLAN-2025-12-29] dynamic-menu-refresh.md
 */

import { useEffect, useRef, useCallback } from 'react';
import { refreshMenus } from '@/lib/utils/menuRefresh';

// 토큰 갱신 신호 쿠키 이름
const TOKEN_REFRESHED_COOKIE = 'token_refreshed_at';

/**
 * 쿠키에서 값 읽기
 */
function getCookieValue(name: string): string | null {
  if (typeof document === 'undefined') return null;
  const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
  return match ? match[2] : null;
}

/**
 * 쿠키 삭제
 */
function deleteCookie(name: string): void {
  if (typeof document === 'undefined') return;
  document.cookie = `${name}=; Path=/; Max-Age=0`;
}

// 기본 폴링 간격: 30초
const DEFAULT_POLLING_INTERVAL = 30 * 1000;

// 최소 폴링 간격: 10초 (서버 부하 방지)
const MIN_POLLING_INTERVAL = 10 * 1000;

// 최대 폴링 간격: 5분
const MAX_POLLING_INTERVAL = 5 * 60 * 1000;

// 세션 만료 판단 기준: 연속 401 횟수
const MAX_SESSION_EXPIRED_COUNT = 3;

interface UseMenuPollingOptions {
  /** 폴링 활성화 여부 (기본: true) */
  enabled?: boolean;
  /** 폴링 간격 (ms, 기본: 30초) */
  interval?: number;
  /** 메뉴 갱신 시 콜백 */
  onMenuUpdated?: () => void;
  /** 에러 발생 시 콜백 */
  onError?: (error: string) => void;
  /** 세션 만료로 폴링 중지 시 콜백 */
  onSessionExpired?: () => void;
}

interface UseMenuPollingReturn {
  /** 수동으로 메뉴 갱신 실행 */
  refresh: () => Promise<void>;
  /** 폴링 일시 중지 */
  pause: () => void;
  /** 폴링 재개 */
  resume: () => void;
  /** 인증 성공 후 폴링 재시작 (401 카운트 리셋) */
  restartAfterAuth: () => void;
  /** 현재 폴링 상태 */
  isPaused: boolean;
  /** 세션 만료로 중지된 상태 */
  isSessionExpired: boolean;
}

/**
 * 메뉴 폴링 훅
 *
 * @example
 * ```tsx
 * // 기본 사용
 * useMenuPolling();
 *
 * // 옵션과 함께 사용
 * const { refresh, pause, resume } = useMenuPolling({
 *   interval: 60000, // 1분마다
 *   onMenuUpdated: () => console.log('메뉴 업데이트됨!'),
 * });
 *
 * // 수동 갱신
 * await refresh();
 * ```
 */
export function useMenuPolling(options: UseMenuPollingOptions = {}): UseMenuPollingReturn {
  const {
    enabled = true,
    interval = DEFAULT_POLLING_INTERVAL,
    onMenuUpdated,
    onError,
    onSessionExpired,
  } = options;

  // 폴링 간격 유효성 검사
  const safeInterval = Math.max(MIN_POLLING_INTERVAL, Math.min(MAX_POLLING_INTERVAL, interval));

  const intervalRef = useRef<NodeJS.Timeout | null>(null);
  const isPausedRef = useRef(false);
  const sessionExpiredCountRef = useRef(0);  // 연속 401 카운트
  const isSessionExpiredRef = useRef(false); // 세션 만료로 중지된 상태

  // 콜백을 ref로 저장하여 인터벌 리셋 방지
  // (인라인 콜백이 매 렌더마다 새 참조를 생성해도 인터벌에 영향 없음)
  const onMenuUpdatedRef = useRef(onMenuUpdated);
  const onErrorRef = useRef(onError);
  const onSessionExpiredRef = useRef(onSessionExpired);

  // 콜백 ref를 최신 값으로 동기화
  useEffect(() => {
    onMenuUpdatedRef.current = onMenuUpdated;
    onErrorRef.current = onError;
    onSessionExpiredRef.current = onSessionExpired;
  });

  // 폴링 중지 (내부용)
  const stopPolling = useCallback(() => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
  }, []);

  // 메뉴 갱신 실행 (의존성: stopPolling만 — 안정적)
  const executeRefresh = useCallback(async () => {
    if (isPausedRef.current || isSessionExpiredRef.current) return;

    const result = await refreshMenus();

    // 성공 시 401 카운트 리셋
    if (result.success) {
      sessionExpiredCountRef.current = 0;

      if (result.updated) {
        onMenuUpdatedRef.current?.();
      }
      return;
    }

    // 401 세션 만료 응답
    if (result.sessionExpired) {
      sessionExpiredCountRef.current += 1;

      // 3회 연속 401 → 폴링 중지
      if (sessionExpiredCountRef.current >= MAX_SESSION_EXPIRED_COUNT) {
        isSessionExpiredRef.current = true;
        stopPolling();
        onSessionExpiredRef.current?.();
      }
      return;
    }

    // 기타 에러 (네트워크 등) → 401 카운트 리셋하지 않음
    if (result.error) {
      onErrorRef.current?.(result.error);
    }
  }, [stopPolling]);

  // 수동 갱신 함수
  const refresh = useCallback(async () => {
    await executeRefresh();
  }, [executeRefresh]);

  // 폴링 일시 중지
  const pause = useCallback(() => {
    isPausedRef.current = true;
    stopPolling();
  }, [stopPolling]);

  // 폴링 재개
  const resume = useCallback(() => {
    // 세션 만료 상태면 재개 불가 (restartAfterAuth 사용)
    if (isSessionExpiredRef.current) {
      return;
    }

    isPausedRef.current = false;
    if (enabled && !intervalRef.current) {
      intervalRef.current = setInterval(executeRefresh, safeInterval);
    }
  }, [enabled, safeInterval, executeRefresh]);

  // 인증 성공 후 폴링 재시작 (401 카운트 리셋)
  const restartAfterAuth = useCallback(() => {
    sessionExpiredCountRef.current = 0;
    isSessionExpiredRef.current = false;
    isPausedRef.current = false;

    if (enabled && !intervalRef.current) {
      // 즉시 한 번 실행 후 폴링 시작
      executeRefresh();
      intervalRef.current = setInterval(executeRefresh, safeInterval);
    }
  }, [enabled, safeInterval, executeRefresh]);

  // 폴링 설정
  useEffect(() => {
    if (!enabled || isSessionExpiredRef.current) {
      stopPolling();
      return;
    }

    // 페이지 로드 시 즉시 실행하지 않음 (로그인 시 이미 받아옴)
    // 폴링 시작
    intervalRef.current = setInterval(executeRefresh, safeInterval);

    return () => {
      stopPolling();
    };
  }, [enabled, safeInterval, executeRefresh, stopPolling]);

  // 탭 가시성 변경 시 처리
  useEffect(() => {
    if (!enabled) return;

    const handleVisibilityChange = () => {
      // 세션 만료 상태면 무시
      if (isSessionExpiredRef.current) return;

      if (document.hidden) {
        // 탭이 숨겨지면 폴링 중지 (리소스 절약)
        stopPolling();
      } else {
        // 탭이 다시 보이면 즉시 갱신 후 폴링 재개
        if (!isPausedRef.current) {
          executeRefresh();
          intervalRef.current = setInterval(executeRefresh, safeInterval);
        }
      }
    };

    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [enabled, safeInterval, executeRefresh, stopPolling]);

  // 🔔 토큰 갱신 신호 쿠키 감지 → 폴링 자동 재시작
  // 서버에서 토큰 갱신 시 설정한 쿠키를 감지하여 폴링을 재시작
  useEffect(() => {
    if (!enabled) return;

    // 마지막으로 처리한 토큰 갱신 타임스탬프 추적
    let lastProcessedTimestamp: string | null = null;

    const checkTokenRefresh = () => {
      const refreshedAt = getCookieValue(TOKEN_REFRESHED_COOKIE);

      // 새로운 토큰 갱신 감지
      if (refreshedAt && refreshedAt !== lastProcessedTimestamp) {
        lastProcessedTimestamp = refreshedAt;

        // 세션 만료 상태였다면 폴링 재시작
        if (isSessionExpiredRef.current) {
          sessionExpiredCountRef.current = 0;
          isSessionExpiredRef.current = false;
          isPausedRef.current = false;

          // 폴링 재시작
          if (!intervalRef.current) {
            executeRefresh();
            intervalRef.current = setInterval(executeRefresh, safeInterval);
          }
        }

        // 쿠키 삭제 (처리 완료)
        deleteCookie(TOKEN_REFRESHED_COOKIE);
      }
    };

    // 1초마다 쿠키 확인
    const checkInterval = setInterval(checkTokenRefresh, 1000);

    return () => {
      clearInterval(checkInterval);
    };
  }, [enabled, safeInterval, executeRefresh]);

  return {
    refresh,
    pause,
    resume,
    restartAfterAuth,
    isPaused: isPausedRef.current,
    isSessionExpired: isSessionExpiredRef.current,
  };
}

export default useMenuPolling;