import { useState, useEffect, useCallback, useRef } from "react";
import { DeviceType, DeviceInfo, BREAKPOINTS } from "./device-detector";

// Advanced device monitoring configuration
export interface DeviceMonitorConfig {
  debounceMs: number;
  throttleMs: number;
  enableOrientationDetection: boolean;
  enableKeyboardDetection: boolean;
  enableMultiScreenDetection: boolean;
  enablePerformanceMonitoring: boolean;
}

const DEFAULT_CONFIG: DeviceMonitorConfig = {
  debounceMs: 250,
  throttleMs: 100,
  enableOrientationDetection: true,
  enableKeyboardDetection: true,
  enableMultiScreenDetection: true,
  enablePerformanceMonitoring: false,
};

// Extended device information with real-time monitoring data
export interface ExtendedDeviceInfo extends DeviceInfo {
  // Real-time monitoring data
  isResizing: boolean;
  isOrientationChanging: boolean;
  isKeyboardVisible: boolean;
  keyboardHeight: number;

  // Performance monitoring
  resizeCount: number;
  lastResizeTime: number;
  averageResizeDelay: number;

  // Multi-screen detection
  screenCount: number;
  currentScreen: number;

  // Connection and hardware info
  connectionType: string;
  hardwareConcurrency: number;
  deviceMemory: number;

  // Battery API (if available)
  batteryLevel?: number;
  isCharging?: boolean;

  // Advanced capabilities
  supportsPWA: boolean;
  supportsWebGL: boolean;
  supportsWebAssembly: boolean;
}

// Custom hook for real-time device monitoring
export const useRealTimeDeviceMonitor = (
  config: Partial<DeviceMonitorConfig> = {}
): ExtendedDeviceInfo => {
  const finalConfig = { ...DEFAULT_CONFIG, ...config };

  // State for extended device info
  const [extendedInfo, setExtendedInfo] = useState<ExtendedDeviceInfo>(() =>
    createExtendedDeviceInfo()
  );

  // Performance monitoring refs
  const resizeCountRef = useRef(0);
  const resizeTimesRef = useRef<number[]>([]);
  const lastResizeTimeRef = useRef(0);

  // Debounce and throttle refs
  const debounceTimeoutRef = useRef<NodeJS.Timeout>();
  const throttleTimeoutRef = useRef<NodeJS.Timeout>();
  const lastThrottleTimeRef = useRef(0);

  // Create extended device info
  function createExtendedDeviceInfo(): ExtendedDeviceInfo {
    if (typeof window === "undefined") {
      return createSSRFallback();
    }

    const basicInfo = createBasicDeviceInfo();
    const keyboardInfo = finalConfig.enableKeyboardDetection
      ? detectKeyboardVisibility()
      : { isKeyboardVisible: false, keyboardHeight: 0 };
    const connectionInfo = getConnectionInfo();
    const hardwareInfo = getHardwareInfo();
    const capabilityInfo = getCapabilityInfo();

    return {
      ...basicInfo,
      ...keyboardInfo,
      ...connectionInfo,
      ...hardwareInfo,
      ...capabilityInfo,
      isResizing: false,
      isOrientationChanging: false,
      resizeCount: resizeCountRef.current,
      lastResizeTime: lastResizeTimeRef.current,
      averageResizeDelay: calculateAverageResizeDelay(),
      screenCount: getScreenCount(),
      currentScreen: getCurrentScreen(),
    };
  }

  // SSR fallback
  function createSSRFallback(): ExtendedDeviceInfo {
    return {
      type: DeviceType.DESKTOP,
      isMobile: false,
      isTablet: false,
      isDesktop: true,
      screenWidth: 1920,
      screenHeight: 1080,
      orientation: "landscape",
      isTouchDevice: false,
      pixelRatio: 1,
      userAgent: "",
      isResizing: false,
      isOrientationChanging: false,
      isKeyboardVisible: false,
      keyboardHeight: 0,
      resizeCount: 0,
      lastResizeTime: 0,
      averageResizeDelay: 0,
      screenCount: 1,
      currentScreen: 0,
      connectionType: "unknown",
      hardwareConcurrency: 4,
      deviceMemory: 4,
      supportsPWA: false,
      supportsWebGL: false,
      supportsWebAssembly: false,
    };
  }

  // Basic device info creation
  function createBasicDeviceInfo(): DeviceInfo {
    const screenWidth = window.innerWidth;
    const screenHeight = window.innerHeight;
    const userAgent = navigator.userAgent;
    const isTouchDevice =
      "ontouchstart" in window || navigator.maxTouchPoints > 0;

    const deviceType = determineDeviceType(
      screenWidth,
      screenHeight,
      userAgent,
      isTouchDevice
    );

    return {
      type: deviceType,
      isMobile: deviceType === DeviceType.MOBILE,
      isTablet: deviceType === DeviceType.TABLET,
      isDesktop: deviceType === DeviceType.DESKTOP,
      screenWidth,
      screenHeight,
      orientation: screenWidth > screenHeight ? "landscape" : "portrait",
      isTouchDevice,
      pixelRatio: window.devicePixelRatio || 1,
      userAgent,
    };
  }

  // Device type determination with improved logic
  function determineDeviceType(
    width: number,
    height: number,
    userAgent: string,
    isTouchDevice: boolean
  ): DeviceType {
    // User agent patterns
    const mobilePattern =
      /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
    const tabletPattern =
      /iPad|Android(?=.*\bTablet\b)|KFAPWI|KFAPWA|KFARWI|KFASWI|KFTHWI|KFTHWA/i;

    // Screen size analysis
    const screenSize = Math.max(width, height);
    const aspectRatio = Math.max(width, height) / Math.min(width, height);

    // Tablet detection (priority)
    if (
      tabletPattern.test(userAgent) ||
      (screenSize >= BREAKPOINTS.mobile &&
        screenSize < BREAKPOINTS.desktop &&
        isTouchDevice &&
        aspectRatio < 2)
    ) {
      return DeviceType.TABLET;
    }

    // Mobile detection
    if (
      mobilePattern.test(userAgent) ||
      (screenSize < BREAKPOINTS.mobile && isTouchDevice)
    ) {
      return DeviceType.MOBILE;
    }

    // Desktop detection with edge cases
    if (
      screenSize >= BREAKPOINTS.desktop ||
      (!isTouchDevice && screenSize >= BREAKPOINTS.tablet)
    ) {
      return DeviceType.DESKTOP;
    }

    // Fallback based on screen size
    if (screenSize < BREAKPOINTS.mobile) return DeviceType.MOBILE;
    if (screenSize < BREAKPOINTS.tablet) return DeviceType.TABLET;
    return DeviceType.DESKTOP;
  }

  // Keyboard visibility detection
  function detectKeyboardVisibility(): {
    isKeyboardVisible: boolean;
    keyboardHeight: number;
  } {
    if (!("visualViewport" in window)) {
      return { isKeyboardVisible: false, keyboardHeight: 0 };
    }

    const visualViewport = window.visualViewport!;
    const keyboardHeight = window.innerHeight - visualViewport.height;
    const isKeyboardVisible = keyboardHeight > 150; // Threshold for keyboard detection

    return { isKeyboardVisible, keyboardHeight };
  }

  // Connection information
  function getConnectionInfo(): { connectionType: string } {
    if ("connection" in navigator) {
      const connection = (navigator as any).connection;
      return { connectionType: connection?.effectiveType || "unknown" };
    }
    return { connectionType: "unknown" };
  }

  // Hardware information
  function getHardwareInfo(): {
    hardwareConcurrency: number;
    deviceMemory: number;
    batteryLevel?: number;
    isCharging?: boolean;
  } {
    const hardwareConcurrency = navigator.hardwareConcurrency || 4;
    const deviceMemory = (navigator as any).deviceMemory || 4;

    return { hardwareConcurrency, deviceMemory };
  }

  // Capability detection
  function getCapabilityInfo(): {
    supportsPWA: boolean;
    supportsWebGL: boolean;
    supportsWebAssembly: boolean;
  } {
    const supportsPWA = "serviceWorker" in navigator && "PushManager" in window;
    const supportsWebGL = !!document
      .createElement("canvas")
      .getContext("webgl");
    const supportsWebAssembly = typeof WebAssembly === "object";

    return { supportsPWA, supportsWebGL, supportsWebAssembly };
  }

  // Screen count detection
  function getScreenCount(): number {
    if ("screen" in window && "getScreens" in (window.screen as any)) {
      // Future API - not widely supported yet
      return 1;
    }
    return 1;
  }

  // Current screen detection
  function getCurrentScreen(): number {
    return 0; // Placeholder for future multi-screen API
  }

  // Calculate average resize delay
  function calculateAverageResizeDelay(): number {
    const times = resizeTimesRef.current;
    if (times.length < 2) return 0;

    const delays = times.slice(1).map((time, index) => time - times[index]);
    return delays.reduce((sum, delay) => sum + delay, 0) / delays.length;
  }

  // Throttled update function
  const throttledUpdate = useCallback(() => {
    const now = Date.now();
    if (now - lastThrottleTimeRef.current < finalConfig.throttleMs) {
      return;
    }

    lastThrottleTimeRef.current = now;

    setExtendedInfo((prevInfo) => ({
      ...createExtendedDeviceInfo(),
      isResizing: true,
    }));
  }, [finalConfig.throttleMs]);

  // Debounced update function
  const debouncedUpdate = useCallback(() => {
    clearTimeout(debounceTimeoutRef.current);
    debounceTimeoutRef.current = setTimeout(() => {
      const now = Date.now();
      resizeCountRef.current++;
      lastResizeTimeRef.current = now;
      resizeTimesRef.current.push(now);

      // Keep only last 10 resize times for performance
      if (resizeTimesRef.current.length > 10) {
        resizeTimesRef.current = resizeTimesRef.current.slice(-10);
      }

      setExtendedInfo((prevInfo) => ({
        ...createExtendedDeviceInfo(),
        isResizing: false,
      }));
    }, finalConfig.debounceMs);
  }, [finalConfig.debounceMs]);

  // Orientation change handler
  const handleOrientationChange = useCallback(() => {
    if (!finalConfig.enableOrientationDetection) return;

    setExtendedInfo((prevInfo) => ({
      ...prevInfo,
      isOrientationChanging: true,
    }));

    setTimeout(() => {
      setExtendedInfo(createExtendedDeviceInfo());
    }, 100);
  }, [finalConfig.enableOrientationDetection]);

  // Setup event listeners
  useEffect(() => {
    // Initial setup
    setExtendedInfo(createExtendedDeviceInfo());

    // Resize event handler
    const handleResize = () => {
      throttledUpdate();
      debouncedUpdate();
    };

    // Event listeners
    window.addEventListener("resize", handleResize);

    if (finalConfig.enableOrientationDetection) {
      window.addEventListener("orientationchange", handleOrientationChange);
      screen.orientation?.addEventListener("change", handleOrientationChange);
    }

    // Visual viewport for keyboard detection
    if (finalConfig.enableKeyboardDetection && "visualViewport" in window) {
      window.visualViewport?.addEventListener("resize", handleResize);
    }

    // Battery monitoring (if available)
    if ("getBattery" in navigator) {
      (navigator as any).getBattery().then((battery: any) => {
        const updateBatteryInfo = () => {
          setExtendedInfo((prevInfo) => ({
            ...prevInfo,
            batteryLevel: battery.level,
            isCharging: battery.charging,
          }));
        };

        battery.addEventListener("levelchange", updateBatteryInfo);
        battery.addEventListener("chargingchange", updateBatteryInfo);
        updateBatteryInfo();
      });
    }

    // Cleanup
    return () => {
      clearTimeout(debounceTimeoutRef.current);
      clearTimeout(throttleTimeoutRef.current);

      window.removeEventListener("resize", handleResize);

      if (finalConfig.enableOrientationDetection) {
        window.removeEventListener(
          "orientationchange",
          handleOrientationChange
        );
        screen.orientation?.removeEventListener(
          "change",
          handleOrientationChange
        );
      }

      if (finalConfig.enableKeyboardDetection && "visualViewport" in window) {
        window.visualViewport?.removeEventListener("resize", handleResize);
      }
    };
  }, [throttledUpdate, debouncedUpdate, handleOrientationChange, finalConfig]);

  return extendedInfo;
};

// Hook for simple device change detection
export const useDeviceChangeDetection = (
  onDeviceChange?: (
    oldInfo: ExtendedDeviceInfo,
    newInfo: ExtendedDeviceInfo
  ) => void
) => {
  const deviceInfo = useRealTimeDeviceMonitor();
  const previousInfoRef = useRef<ExtendedDeviceInfo>(deviceInfo);

  useEffect(() => {
    const prevInfo = previousInfoRef.current;
    const currentInfo = deviceInfo;

    // Check for significant changes
    const hasSignificantChange =
      prevInfo.type !== currentInfo.type ||
      prevInfo.orientation !== currentInfo.orientation ||
      Math.abs(prevInfo.screenWidth - currentInfo.screenWidth) > 50 ||
      Math.abs(prevInfo.screenHeight - currentInfo.screenHeight) > 50;

    if (hasSignificantChange && onDeviceChange) {
      onDeviceChange(prevInfo, currentInfo);
    }

    previousInfoRef.current = currentInfo;
  }, [deviceInfo, onDeviceChange]);

  return deviceInfo;
};

// Hook for performance monitoring
export const useDevicePerformanceMonitor = () => {
  const deviceInfo = useRealTimeDeviceMonitor({
    enablePerformanceMonitoring: true,
  });

  const performanceMetrics = {
    averageResizeDelay: deviceInfo.averageResizeDelay,
    resizeFrequency: deviceInfo.resizeCount,
    isHighPerformanceDevice:
      deviceInfo.hardwareConcurrency >= 8 && deviceInfo.deviceMemory >= 8,
    isLowEndDevice:
      deviceInfo.hardwareConcurrency <= 2 && deviceInfo.deviceMemory <= 2,
    networkQuality: deviceInfo.connectionType,
    supportsAdvancedFeatures:
      deviceInfo.supportsWebGL && deviceInfo.supportsWebAssembly,
  };

  return { deviceInfo, performanceMetrics };
};

export default useRealTimeDeviceMonitor;
