import React from 'react';
import { requireNativeComponent, ViewStyle, NativeSyntheticEvent, UIManager, findNodeHandle, Platform } from 'react-native';
import { 
  ARTrackingState, 
  ARPlaneEvent, 
  ARObjectEvent, 
  ARTapEvent, 
  ARDepthUpdateEvent, 
  ARObjectModel,
  ARLightEstimationEvent,
  ARLightEstimationMode,
  ARLightConfiguration,
  ARShadowConfiguration,
  ARShadowQuality
} from './types';

const LINKING_ERROR =
  `The package 'react-native-ar' doesn't seem to be linked. Make sure: \n\n` +
  '- You have run "npm install" or "yarn"\n' +
  '- You rebuilt the app after installing the package\n' +
  '- You are not using Expo Go\n';

const ComponentName = 'ARView';

// Check if the native module exists through UIManager
const isTurboModuleEnabled = global.__turboModuleProxy != null;

const ARViewNative = isTurboModuleEnabled
  ? require('./NativeARModule').default.getViewManager(ComponentName)
  : UIManager.getViewManagerConfig(ComponentName) != null
  ? requireNativeComponent<NativeARViewProps>(ComponentName)
  : () => {
      throw new Error(LINKING_ERROR);
    };

export interface ARViewProps {
  /**
   * Style for the AR view
   */
  style?: ViewStyle;
  
  /**
   * Callback for tracking state changes
   */
  onTrackingUpdated?: (state: ARTrackingState) => void;
  
  /**
   * Callback when a new plane is detected
   */
  onPlaneDetected?: (event: ARPlaneEvent) => void;
  
  /**
   * Callback when an object is placed
   */
  onObjectPlaced?: (event: ARObjectEvent) => void;
  
  /**
   * Callback when the user taps
   */
  onTap?: (event: ARTapEvent) => void;
  
  /**
   * Whether to place an object when the user taps
   */
  placeOnTap?: boolean;
  
  /**
   * Scale factor for placed objects
   */
  objectScale?: number;
  
  /**
   * Whether to enable depth-based occlusion
   */
  enableDepthOcclusion?: boolean;
  
  /**
   * Whether to visualize depth information for debugging
   */
  occlusionDebugMode?: boolean;
  
  /**
   * Callback with depth information at the center of the screen
   */
  onDepthUpdated?: (event: ARDepthUpdateEvent) => void;
  
  /**
   * Whether to show AR feature points
   */
  showFeaturePoints?: boolean;
  
  /**
   * Whether to visualize detected planes
   */
  showPlanes?: boolean;
  
  /**
   * Default 3D model to place on tap
   * If not provided, a default cube model will be used
   */
  defaultModel?: ARObjectModel;
  
  /**
   * Whether to allow model manipulation (rotation, scaling)
   */
  allowModelManipulation?: boolean;
  
  /**
   * Whether to enable model shadows (deprecated, use shadowConfiguration instead)
   */
  enableShadows?: boolean;
  
  /**
   * Advanced shadow configuration for rendering
   */
  shadowConfiguration?: ARShadowConfiguration;
  
  /**
   * Maximum number of models that can be placed
   * Set to 0 for unlimited
   */
  maxModels?: number;
  
  /**
   * Whether to automatically estimate lighting for realistic rendering
   * (deprecated, use lightingConfiguration instead)
   */
  enableLightEstimation?: boolean;
  
  /**
   * Advanced lighting configuration for adaptive lighting
   */
  lightingConfiguration?: {
    /**
     * Light estimation mode for environmental lighting
     */
    estimationMode?: ARLightEstimationMode;
    
    /**
     * Additional manual lights to add to the scene
     */
    additionalLights?: ARLightConfiguration[];
    
    /**
     * Whether to debug visualize the lights
     */
    debugVisualization?: boolean;
    
    /**
     * Whether to use environment probes for PBR reflections
     */
    useEnvironmentProbes?: boolean;
  };
  
  /**
   * Callback for light estimation updates 
   */
  onLightEstimationUpdated?: (event: ARLightEstimationEvent) => void;
  
  /**
   * Callback when model manipulation starts (selection, moving, etc.)
   */
  onModelManipulationStart?: (objectId: string) => void;
  
  /**
   * Callback when model manipulation ends
   */
  onModelManipulationEnd?: (objectId: string) => void;
  
  /**
   * Callback when a model fails to load
   */
  onModelLoadError?: (error: {modelUri: string, message: string}) => void;
}

interface NativeARViewProps extends ARViewProps {
  onTrackingUpdatedNative?: (event: NativeSyntheticEvent<ARTrackingState>) => void;
  onPlaneDetectedNative?: (event: NativeSyntheticEvent<ARPlaneEvent>) => void;
  onObjectPlacedNative?: (event: NativeSyntheticEvent<ARObjectEvent>) => void;
  onTapNative?: (event: NativeSyntheticEvent<ARTapEvent>) => void;
  onDepthUpdatedNative?: (event: NativeSyntheticEvent<ARDepthUpdateEvent>) => void;
  onLightEstimationUpdatedNative?: (event: NativeSyntheticEvent<ARLightEstimationEvent>) => void;
  onModelManipulationStartNative?: (event: NativeSyntheticEvent<{objectId: string}>) => void;
  onModelManipulationEndNative?: (event: NativeSyntheticEvent<{objectId: string}>) => void;
  onModelLoadErrorNative?: (event: NativeSyntheticEvent<{modelUri: string, message: string}>) => void;
}

/**
 * A React Native component that displays AR content
 */
export const ARView: React.FC<ARViewProps> = ({
  onTrackingUpdated,
  onPlaneDetected,
  onObjectPlaced,
  onTap,
  onDepthUpdated,
  onLightEstimationUpdated,
  onModelManipulationStart,
  onModelManipulationEnd,
  onModelLoadError,
  placeOnTap = true,
  objectScale = 1.0,
  enableDepthOcclusion = false,
  occlusionDebugMode = false,
  showFeaturePoints = false,
  showPlanes = false,
  defaultModel = undefined,
  allowModelManipulation = true,
  enableShadows = true,
  shadowConfiguration = undefined,
  maxModels = 0,
  enableLightEstimation = true,
  lightingConfiguration = undefined,
  ...props
}) => {
  const viewRef = React.useRef(null);

  const onTrackingUpdatedNative = (event: NativeSyntheticEvent<ARTrackingState>) => {
    onTrackingUpdated?.(event.nativeEvent);
  };

  const onPlaneDetectedNative = (event: NativeSyntheticEvent<ARPlaneEvent>) => {
    onPlaneDetected?.(event.nativeEvent);
  };

  const onObjectPlacedNative = (event: NativeSyntheticEvent<ARObjectEvent>) => {
    onObjectPlaced?.(event.nativeEvent);
  };

  const onTapNative = (event: NativeSyntheticEvent<ARTapEvent>) => {
    onTap?.(event.nativeEvent);
  };

  const onDepthUpdatedNative = (event: NativeSyntheticEvent<ARDepthUpdateEvent>) => {
    onDepthUpdated?.(event.nativeEvent);
  };
  
  const onLightEstimationUpdatedNative = (event: NativeSyntheticEvent<ARLightEstimationEvent>) => {
    onLightEstimationUpdated?.(event.nativeEvent);
  };
  
  const onModelManipulationStartNative = (event: NativeSyntheticEvent<{objectId: string}>) => {
    onModelManipulationStart?.(event.nativeEvent.objectId);
  };
  
  const onModelManipulationEndNative = (event: NativeSyntheticEvent<{objectId: string}>) => {
    onModelManipulationEnd?.(event.nativeEvent.objectId);
  };
  
  const onModelLoadErrorNative = (event: NativeSyntheticEvent<{modelUri: string, message: string}>) => {
    onModelLoadError?.(event.nativeEvent);
  };

  // Preload the default model if provided
  React.useEffect(() => {
    if (defaultModel && viewRef.current) {
      // This would call a native method to preload the model
      const nodeHandle = findNodeHandle(viewRef.current);
      if (nodeHandle && UIManager.dispatchViewManagerCommand) {
        UIManager.dispatchViewManagerCommand(
          nodeHandle,
          // @ts-ignore - Command name mapping handled by native side
          UIManager.getViewManagerConfig(ComponentName).Commands.preloadDefaultModel,
          [defaultModel]
        );
      }
    }
  }, [defaultModel]);

  return (
    <ARViewNative
      ref={viewRef}
      placeOnTap={placeOnTap}
      objectScale={objectScale}
      enableDepthOcclusion={enableDepthOcclusion}
      occlusionDebugMode={occlusionDebugMode}
      showFeaturePoints={showFeaturePoints}
      showPlanes={showPlanes}
      defaultModel={defaultModel}
      allowModelManipulation={allowModelManipulation}
      enableShadows={enableShadows}
      maxModels={maxModels}
      enableLightEstimation={enableLightEstimation}
      onTrackingUpdatedNative={onTrackingUpdated ? onTrackingUpdatedNative : undefined}
      onPlaneDetectedNative={onPlaneDetected ? onPlaneDetectedNative : undefined}
      onObjectPlacedNative={onObjectPlaced ? onObjectPlacedNative : undefined}
      onTapNative={onTap ? onTapNative : undefined}
      onDepthUpdatedNative={onDepthUpdated ? onDepthUpdatedNative : undefined}
      onLightEstimationUpdatedNative={onLightEstimationUpdated ? onLightEstimationUpdatedNative : undefined}
      onModelManipulationStartNative={onModelManipulationStart ? onModelManipulationStartNative : undefined}
      onModelManipulationEndNative={onModelManipulationEnd ? onModelManipulationEndNative : undefined}
      onModelLoadErrorNative={onModelLoadError ? onModelLoadErrorNative : undefined}
      shadowConfiguration={shadowConfiguration}
      lightingConfiguration={lightingConfiguration}
      {...props}
    />
  );
};
