import { useEffect, useRef, useCallback } from 'react';
import {
  NativeModules,
  NativeEventEmitter,
  Platform,
} from 'react-native';
import { logger } from '@/src/shared/utils/logger';
import type {
  WorkoutState,
  WatchControlAction,
  WatchAvailability,
  WatchControlMessage,
} from './types';

const { WatchBridge } = NativeModules;

interface UseWatchSyncOptions {
  onPlay?: () => void;
  onPause?: () => void;
  onSkip?: () => void;
  onStop?: () => void;
  onPrevious?: () => void;
  onHeartRateUpdate?: (heartRate: number) => void;
  enabled?: boolean;
}

interface UseWatchSyncReturn {
  isAvailable: boolean;
  isReachable: boolean;
  sendWorkoutState: (state: WorkoutState) => void;
  checkAvailability: () => Promise<WatchAvailability>;
}

/**
 * Hook to sync workout state with Apple Watch
 * 
 * @example
 * ```tsx
 * const { isAvailable, sendWorkoutState } = useWatchSync({
 *   onPlay: () => resume(),
 *   onPause: () => pause(),
 *   onSkip: () => skip(),
 *   onStop: () => stop(),
 * });
 * 
 * // Send state updates
 * useEffect(() => {
 *   if (isAvailable && isRunning) {
 *     sendWorkoutState({
 *       phase,
 *       timeRemaining,
 *       currentRound,
 *       totalRounds,
 *       currentExercise,
 *       nextExercise,
 *       calories,
 *       isPaused,
 *       isPlaying: isRunning && !isPaused,
 *     });
 *   }
 * }, [phase, timeRemaining, currentRound, isPaused]);
 * ```
 */
export function useWatchSync(options: UseWatchSyncOptions = {}): UseWatchSyncReturn {
  const {
    onPlay,
    onPause,
    onSkip,
    onStop,
    onPrevious,
    onHeartRateUpdate,
    enabled = true,
  } = options;

  const isAvailableRef = useRef(false);
  const isReachableRef = useRef(false);
  const eventEmitterRef = useRef<NativeEventEmitter | null>(null);

  // Initialize event emitter
  useEffect(() => {
    if (Platform.OS !== 'ios' || !enabled) return;

    if (!WatchBridge) {
      logger.warn('WatchBridge native module not found');
      return;
    }

    eventEmitterRef.current = new NativeEventEmitter(WatchBridge);

    return () => {
      // Cleanup will be handled by individual subscriptions
    };
  }, [enabled]);

  // Listen for control events from Watch
  useEffect(() => {
    if (!eventEmitterRef.current || !enabled) return;

    const subscriptions: { remove(): void }[] = [];

    // Listen for control commands from Watch
    const controlSubscription = eventEmitterRef.current.addListener(
      'WatchControlReceived',
      (data: { action: WatchControlAction }) => {
        logger.log('Received control from Watch:', data.action);
        
        switch (data.action) {
          case 'play':
            onPlay?.();
            break;
          case 'pause':
            onPause?.();
            break;
          case 'skip':
            onSkip?.();
            break;
          case 'stop':
            onStop?.();
            break;
          case 'previous':
            onPrevious?.();
            break;
        }
      }
    );
    subscriptions.push(controlSubscription);

    // Listen for connectivity status changes
    const statusSubscription = eventEmitterRef.current.addListener(
      'WatchConnectivityStatus',
      (data: { reachable: boolean }) => {
        logger.log('Watch connectivity changed:', data.reachable);
        isReachableRef.current = data.reachable;
      }
    );
    subscriptions.push(statusSubscription);

    // Listen for general messages (including heart rate)
    const messageSubscription = eventEmitterRef.current.addListener(
      'WatchMessageReceived',
      (data: { type: string; value?: number }) => {
        if (data.type === 'heartRate' && typeof data.value === 'number') {
          onHeartRateUpdate?.(data.value);
        }
      }
    );
    subscriptions.push(messageSubscription);

    // Listen for watch state changes
    const stateSubscription = eventEmitterRef.current.addListener(
      'WatchStateChanged',
      (data: { isReachable: boolean; isWatchAppInstalled: boolean }) => {
        logger.log('Watch state changed:', data);
        isReachableRef.current = data.isReachable;
        isAvailableRef.current = data.isWatchAppInstalled;
      }
    );
    subscriptions.push(stateSubscription);

    return () => {
      subscriptions.forEach(sub => sub.remove());
    };
  }, [enabled, onPlay, onPause, onSkip, onStop, onPrevious, onHeartRateUpdate]);

  // Check initial availability
  useEffect(() => {
    if (Platform.OS !== 'ios' || !enabled || !WatchBridge) return;

    checkAvailability().catch(logger.error);
  }, [enabled]);

  const checkAvailability = useCallback(async (): Promise<WatchAvailability> => {
    if (Platform.OS !== 'ios' || !WatchBridge) {
      return {
        isSupported: false,
        isPaired: false,
        isWatchAppInstalled: false,
        isReachable: false,
      };
    }

    try {
      const availability = await WatchBridge.isWatchAvailable();
      isAvailableRef.current = availability.isWatchAppInstalled;
      isReachableRef.current = availability.isReachable;
      return availability;
    } catch (error) {
      logger.error('Failed to check Watch availability:', error);
      return {
        isSupported: false,
        isPaired: false,
        isWatchAppInstalled: false,
        isReachable: false,
      };
    }
  }, []);

  const sendWorkoutState = useCallback((state: WorkoutState) => {
    if (Platform.OS !== 'ios' || !WatchBridge || !isReachableRef.current) {
      return;
    }

    try {
      WatchBridge.sendWorkoutState(state);
    } catch (error) {
      logger.error('Failed to send workout state:', error);
    }
  }, []);

  return {
    isAvailable: isAvailableRef.current,
    isReachable: isReachableRef.current,
    sendWorkoutState,
    checkAvailability,
  };
}
