/**
 * useNetworkAware Hook
 *
 * Monitors network conditions and adapts preloading strategy accordingly.
 * Uses the Network Information API where available.
 */

import { useState, useEffect, useCallback } from 'react';
import type { NetworkInfo } from '../types/offline';

// Extend Navigator interface for Network Information API
interface NetworkInformation extends EventTarget {
  readonly effectiveType?: 'slow-2g' | '2g' | '3g' | '4g';
  readonly downlink?: number;
  readonly rtt?: number;
  readonly saveData?: boolean;
  onchange?: () => void;
}

interface NavigatorWithConnection extends Navigator {
  connection?: NetworkInformation;
  mozConnection?: NetworkInformation;
  webkitConnection?: NetworkInformation;
}

interface UseNetworkAwareResult {
  networkInfo: NetworkInfo;
  /**
   * Whether preloading should be aggressive (good connection)
   */
  shouldPreloadAggressively: boolean;
  /**
   * Whether to prefer lower quality variants
   */
  preferLowQuality: boolean;
  /**
   * Recommended concurrent download count based on network
   */
  recommendedConcurrency: number;
  /**
   * Whether offline mode should be suggested to user
   */
  suggestOfflineMode: boolean;
}

const getConnection = (): NetworkInformation | null => {
  if (typeof navigator === 'undefined') return null;
  const nav = navigator as NavigatorWithConnection;
  return nav.connection || nav.mozConnection || nav.webkitConnection || null;
};

const getNetworkInfo = (): NetworkInfo => {
  if (typeof navigator === 'undefined') {
    return { isOnline: true };
  }

  const connection = getConnection();

  return {
    isOnline: navigator.onLine,
    effectiveType: connection?.effectiveType,
    downlink: connection?.downlink,
    rtt: connection?.rtt,
    saveData: connection?.saveData,
  };
};

export function useNetworkAware(): UseNetworkAwareResult {
  const [networkInfo, setNetworkInfo] = useState<NetworkInfo>(getNetworkInfo);

  // Update network info on changes
  useEffect(() => {
    if (typeof window === 'undefined') return;

    const updateNetworkInfo = () => {
      setNetworkInfo(getNetworkInfo());
    };

    // Listen for online/offline events
    window.addEventListener('online', updateNetworkInfo);
    window.addEventListener('offline', updateNetworkInfo);

    // Listen for connection changes if available
    const connection = getConnection();
    if (connection) {
      connection.addEventListener('change', updateNetworkInfo);
    }

    return () => {
      window.removeEventListener('online', updateNetworkInfo);
      window.removeEventListener('offline', updateNetworkInfo);
      if (connection) {
        connection.removeEventListener('change', updateNetworkInfo);
      }
    };
  }, []);

  // Determine if preloading should be aggressive
  const shouldPreloadAggressively = useCallback((): boolean => {
    if (!networkInfo.isOnline) return false;
    if (networkInfo.saveData) return false;

    // Good connection: 4g or high downlink
    if (networkInfo.effectiveType === '4g') return true;
    if (networkInfo.downlink && networkInfo.downlink >= 5) return true;

    return false;
  }, [networkInfo]);

  // Determine if low quality variants should be preferred
  const preferLowQuality = useCallback((): boolean => {
    if (networkInfo.saveData) return true;
    if (networkInfo.effectiveType === 'slow-2g') return true;
    if (networkInfo.effectiveType === '2g') return true;
    if (networkInfo.downlink && networkInfo.downlink < 1) return true;

    return false;
  }, [networkInfo]);

  // Calculate recommended concurrency
  const getRecommendedConcurrency = useCallback((): number => {
    if (!networkInfo.isOnline) return 0;
    if (networkInfo.saveData) return 1;

    switch (networkInfo.effectiveType) {
      case 'slow-2g':
        return 1;
      case '2g':
        return 1;
      case '3g':
        return 2;
      case '4g':
        return 3;
      default:
        // Fall back to downlink-based calculation
        if (networkInfo.downlink) {
          if (networkInfo.downlink < 1) return 1;
          if (networkInfo.downlink < 5) return 2;
          return 3;
        }
        return 2; // Default
    }
  }, [networkInfo]);

  // Determine if offline mode should be suggested
  const suggestOfflineMode = useCallback((): boolean => {
    // Suggest offline if on poor connection
    if (networkInfo.effectiveType === 'slow-2g') return true;
    if (networkInfo.effectiveType === '2g') return true;
    if (networkInfo.rtt && networkInfo.rtt > 500) return true;
    if (networkInfo.downlink && networkInfo.downlink < 0.5) return true;

    return false;
  }, [networkInfo]);

  return {
    networkInfo,
    shouldPreloadAggressively: shouldPreloadAggressively(),
    preferLowQuality: preferLowQuality(),
    recommendedConcurrency: getRecommendedConcurrency(),
    suggestOfflineMode: suggestOfflineMode(),
  };
}
