'use client';

/**
 * Token Refresh Hook
 *
 * Provides automatic token refresh functionality:
 * - Proactively refreshes token before expiry
 * - Refreshes on window focus
 * - Refreshes on network reconnect
 */

import { useCallback, useEffect, useRef } from 'react';
import { api as apiAccounts } from '../../';
import { authLogger } from '../utils/logger';

// Configuration
const TOKEN_REFRESH_THRESHOLD_MS = 10 * 60 * 1000; // 10 minutes before expiry
const CHECK_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes

interface UseTokenRefreshOptions {
  /** Enable automatic token refresh (default: true) */
  enabled?: boolean;
  /** Callback when token is refreshed */
  onRefresh?: (newToken: string) => void;
  /** Callback when refresh fails */
  onRefreshError?: (error: Error) => void;
}

/**
 * Decode JWT and get expiry time
 */
function getTokenExpiry(token: string): number | null {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    return payload.exp * 1000; // Convert to milliseconds
  } catch {
    return null;
  }
}

/**
 * Check if token is expiring soon
 */
function isTokenExpiringSoon(token: string, thresholdMs: number): boolean {
  const expiry = getTokenExpiry(token);
  if (!expiry) return false;

  const timeUntilExpiry = expiry - Date.now();
  return timeUntilExpiry < thresholdMs;
}

/**
 * Hook for automatic token refresh
 */
export function useTokenRefresh(options: UseTokenRefreshOptions = {}) {
  const { enabled = true, onRefresh, onRefreshError } = options;
  const isRefreshingRef = useRef(false);

  /**
   * Refresh the token
   */
  const refreshToken = useCallback(async (): Promise<boolean> => {
    if (isRefreshingRef.current) {
      authLogger.debug('Token refresh already in progress');
      return false;
    }

    const refreshTokenValue = apiAccounts.getRefreshToken();
    if (!refreshTokenValue) {
      authLogger.warn('No refresh token available');
      return false;
    }

    isRefreshingRef.current = true;
    authLogger.info('Refreshing token...');

    try {
      // Use generated API client with correct URL (/cfg/accounts/token/refresh/)
      const result = await apiAccounts.auth.accountsTokenRefreshCreate({
        refresh: refreshTokenValue,
      });

      const newAccessToken = result.access;

      if (!newAccessToken) {
        throw new Error('No access token in refresh response');
      }

      apiAccounts.setToken(newAccessToken, refreshTokenValue);
      authLogger.info('Token refreshed successfully');

      onRefresh?.(newAccessToken);
      return true;
    } catch (error) {
      authLogger.error('Token refresh error:', error);
      onRefreshError?.(error instanceof Error ? error : new Error(String(error)));
      return false;
    } finally {
      isRefreshingRef.current = false;
    }
  }, [onRefresh, onRefreshError]);

  /**
   * Check and refresh if needed
   */
  const checkAndRefresh = useCallback(async () => {
    const token = apiAccounts.getToken();
    if (!token) return;

    if (isTokenExpiringSoon(token, TOKEN_REFRESH_THRESHOLD_MS)) {
      authLogger.info('Token expiring soon, refreshing proactively');
      await refreshToken();
    }
  }, [refreshToken]);

  // Periodic check
  useEffect(() => {
    if (!enabled) return;

    // Check immediately
    checkAndRefresh();

    // Set up interval
    const intervalId = setInterval(checkAndRefresh, CHECK_INTERVAL_MS);

    return () => clearInterval(intervalId);
  }, [enabled, checkAndRefresh]);

  // Refresh on window focus
  useEffect(() => {
    if (!enabled) return;

    const handleFocus = () => {
      authLogger.debug('Window focused, checking token...');
      checkAndRefresh();
    };

    window.addEventListener('focus', handleFocus);
    return () => window.removeEventListener('focus', handleFocus);
  }, [enabled, checkAndRefresh]);

  // Refresh on network reconnect
  useEffect(() => {
    if (!enabled) return;

    const handleOnline = () => {
      authLogger.info('Network reconnected, checking token...');
      checkAndRefresh();
    };

    window.addEventListener('online', handleOnline);
    return () => window.removeEventListener('online', handleOnline);
  }, [enabled, checkAndRefresh]);

  return {
    refreshToken,
    checkAndRefresh,
  };
}

export default useTokenRefresh;
