import React, {
  createContext,
  useContext,
  useState,
  useEffect,
  useCallback,
} from "react";

// Device types enum for better type safety
export enum DeviceType {
  DESKTOP = "desktop",
  TABLET = "tablet",
  MOBILE = "mobile",
}

// Screen size breakpoints configuration
export const BREAKPOINTS = {
  mobile: 768,
  tablet: 1024,
  desktop: 1200,
} as const;

// Device detection result interface
export interface DeviceInfo {
  type: DeviceType;
  isMobile: boolean;
  isTablet: boolean;
  isDesktop: boolean;
  screenWidth: number;
  screenHeight: number;
  orientation: "portrait" | "landscape";
  isTouchDevice: boolean;
  pixelRatio: number;
  userAgent: string;
}

// Context for device detection
interface DeviceDetectorContextType {
  deviceInfo: DeviceInfo;
  isLoading: boolean;
  forceRefresh: () => void;
}

const DeviceDetectorContext = createContext<
  DeviceDetectorContextType | undefined
>(undefined);

// Utility functions for device detection
const getUserAgent = (): string => {
  if (typeof window === "undefined") return "";
  return window.navigator.userAgent;
};

const isTouchSupported = (): boolean => {
  if (typeof window === "undefined") return false;
  return "ontouchstart" in window || navigator.maxTouchPoints > 0;
};

const getMobileUserAgentPattern = (): RegExp => {
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
};

const getTabletUserAgentPattern = (): RegExp => {
  return /iPad|Android(?=.*\bMobile\b)(?=.*\bTablet\b)|KFAPWI|KFAPWA|KFARWI|KFASWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFGIWI|KFMEWI/i;
};

const detectDeviceFromUserAgent = (userAgent: string): DeviceType => {
  if (getTabletUserAgentPattern().test(userAgent)) {
    return DeviceType.TABLET;
  }
  if (getMobileUserAgentPattern().test(userAgent)) {
    return DeviceType.MOBILE;
  }
  return DeviceType.DESKTOP;
};

const detectDeviceFromScreenSize = (
  width: number,
  height: number
): DeviceType => {
  const screenSize = Math.max(width, height);

  if (screenSize < BREAKPOINTS.mobile) {
    return DeviceType.MOBILE;
  }
  if (screenSize < BREAKPOINTS.tablet) {
    return DeviceType.TABLET;
  }
  return DeviceType.DESKTOP;
};

const getOrientation = (
  width: number,
  height: number
): "portrait" | "landscape" => {
  return width > height ? "landscape" : "portrait";
};

const createDeviceInfo = (): DeviceInfo => {
  if (typeof window === "undefined") {
    // Server-side rendering fallback
    return {
      type: DeviceType.DESKTOP,
      isMobile: false,
      isTablet: false,
      isDesktop: true,
      screenWidth: 1920,
      screenHeight: 1080,
      orientation: "landscape",
      isTouchDevice: false,
      pixelRatio: 1,
      userAgent: "",
    };
  }

  const screenWidth = window.innerWidth;
  const screenHeight = window.innerHeight;
  const userAgent = getUserAgent();
  const isTouchDevice = isTouchSupported();

  // Combine user agent and screen size detection for accuracy
  const deviceFromUA = detectDeviceFromUserAgent(userAgent);
  const deviceFromScreen = detectDeviceFromScreenSize(
    screenWidth,
    screenHeight
  );

  // Priority logic: user agent detection takes precedence, but screen size can override for edge cases
  let finalDeviceType = deviceFromUA;

  // Special case: if user agent says mobile but screen is very large, it might be desktop
  if (
    deviceFromUA === DeviceType.MOBILE &&
    screenWidth > BREAKPOINTS.tablet &&
    !isTouchDevice
  ) {
    finalDeviceType = DeviceType.DESKTOP;
  }

  // Special case: if user agent says desktop but screen is small and touch-enabled, likely mobile
  if (
    deviceFromUA === DeviceType.DESKTOP &&
    screenWidth < BREAKPOINTS.mobile &&
    isTouchDevice
  ) {
    finalDeviceType = DeviceType.MOBILE;
  }

  return {
    type: finalDeviceType,
    isMobile: finalDeviceType === DeviceType.MOBILE,
    isTablet: finalDeviceType === DeviceType.TABLET,
    isDesktop: finalDeviceType === DeviceType.DESKTOP,
    screenWidth,
    screenHeight,
    orientation: getOrientation(screenWidth, screenHeight),
    isTouchDevice,
    pixelRatio: window.devicePixelRatio || 1,
    userAgent,
  };
};

// Custom hook for device detection
export const useDeviceDetection = (): DeviceDetectorContextType => {
  const context = useContext(DeviceDetectorContext);
  if (context === undefined) {
    throw new Error(
      "useDeviceDetection must be used within a DeviceDetectorProvider"
    );
  }
  return context;
};

// Legacy hook for backward compatibility
export const useIsMobile = (): boolean => {
  const { deviceInfo } = useDeviceDetection();
  return deviceInfo.isMobile;
};

// Device detector provider component
interface DeviceDetectorProviderProps {
  children: React.ReactNode;
  debounceMs?: number;
  enableLogging?: boolean;
}

export const DeviceDetectorProvider: React.FC<DeviceDetectorProviderProps> = ({
  children,
  debounceMs = 250,
  enableLogging = false,
}) => {
  const [deviceInfo, setDeviceInfo] = useState<DeviceInfo>(createDeviceInfo);
  const [isLoading, setIsLoading] = useState(true);

  const updateDeviceInfo = useCallback(() => {
    const newDeviceInfo = createDeviceInfo();

    if (enableLogging) {
      console.log("Device detection updated:", newDeviceInfo);
    }

    setDeviceInfo(newDeviceInfo);
    setIsLoading(false);
  }, [enableLogging]);

  const forceRefresh = useCallback(() => {
    setIsLoading(true);
    updateDeviceInfo();
  }, [updateDeviceInfo]);

  useEffect(() => {
    // Initial detection
    updateDeviceInfo();

    // Debounced resize handler
    let timeoutId: NodeJS.Timeout;

    const handleResize = () => {
      clearTimeout(timeoutId);
      setIsLoading(true);
      timeoutId = setTimeout(() => {
        updateDeviceInfo();
      }, debounceMs);
    };

    // Listen for screen size changes
    window.addEventListener("resize", handleResize);
    window.addEventListener("orientationchange", handleResize);

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

    return () => {
      clearTimeout(timeoutId);
      window.removeEventListener("resize", handleResize);
      window.removeEventListener("orientationchange", handleResize);

      if ("visualViewport" in window) {
        window.visualViewport?.removeEventListener("resize", handleResize);
      }
    };
  }, [updateDeviceInfo, debounceMs]);

  const contextValue: DeviceDetectorContextType = {
    deviceInfo,
    isLoading,
    forceRefresh,
  };

  return (
    <DeviceDetectorContext.Provider value={contextValue}>
      {children}
    </DeviceDetectorContext.Provider>
  );
};

// Utility component for conditional rendering
interface DeviceConditionalProps {
  mobile?: React.ReactNode;
  tablet?: React.ReactNode;
  desktop?: React.ReactNode;
  fallback?: React.ReactNode;
}

export const DeviceConditional: React.FC<DeviceConditionalProps> = ({
  mobile,
  tablet,
  desktop,
  fallback,
}) => {
  const { deviceInfo } = useDeviceDetection();

  switch (deviceInfo.type) {
    case DeviceType.MOBILE:
      return mobile ? <>{mobile}</> : fallback ? <>{fallback}</> : null;
    case DeviceType.TABLET:
      return tablet ? <>{tablet}</> : fallback ? <>{fallback}</> : null;
    case DeviceType.DESKTOP:
      return desktop ? <>{desktop}</> : fallback ? <>{fallback}</> : null;
    default:
      return fallback ? <>{fallback}</> : null;
  }
};

// Debug component for development
export const DeviceDetectionDebug: React.FC = () => {
  const { deviceInfo, isLoading, forceRefresh } = useDeviceDetection();

  if (process.env.NODE_ENV === "production") {
    return null;
  }

  return (
    <div
      style={{
        position: "fixed",
        top: 10,
        right: 10,
        background: "rgba(0, 0, 0, 0.8)",
        color: "white",
        padding: "10px",
        borderRadius: "5px",
        fontSize: "12px",
        fontFamily: "monospace",
        zIndex: 9999,
        maxWidth: "300px",
      }}
    >
      <div style={{ marginBottom: "5px" }}>
        <strong>Device Detection {isLoading && "(Loading...)"}</strong>
        <button
          onClick={forceRefresh}
          style={{
            marginLeft: "10px",
            padding: "2px 6px",
            fontSize: "10px",
            background: "white",
            color: "black",
            border: "none",
            borderRadius: "3px",
            cursor: "pointer",
          }}
        >
          Refresh
        </button>
      </div>
      <div>Type: {deviceInfo.type}</div>
      <div>
        Screen: {deviceInfo.screenWidth}x{deviceInfo.screenHeight}
      </div>
      <div>Orientation: {deviceInfo.orientation}</div>
      <div>Touch: {deviceInfo.isTouchDevice ? "Yes" : "No"}</div>
      <div>Pixel Ratio: {deviceInfo.pixelRatio}</div>
      <div>UA: {deviceInfo.userAgent.substring(0, 50)}...</div>
    </div>
  );
};

export default DeviceDetectorProvider;
