import { useCallback, useEffect, useRef } from 'react';
import { usePersSDK } from '../providers/PersSDKProvider';
import type { 
  PersEvent, 
  EventHandler, 
  EventFilter,
  Unsubscribe 
} from '@explorins/pers-sdk/core';

// Re-export event types for convenience
export type { PersEvent, EventHandler, EventFilter, Unsubscribe };

/**
 * Return interface for the useEvents hook
 * 
 * Provides event subscription capabilities for the PERS SDK event system.
 * Use this to display notifications, update UI, or trigger side effects.
 * 
 * @interface EventsHook
 * @property {Function} subscribe - Subscribe to SDK events with optional filtering
 * @property {Function} once - Subscribe to a single event (auto-unsubscribes)
 * @property {Function} clear - Clear all subscriptions
 * @property {boolean} isAvailable - Whether the event system is available
 * @property {number} subscriberCount - Current number of active subscribers
 */
export interface EventsHook {
  subscribe: (handler: EventHandler, filter?: EventFilter) => Unsubscribe;
  once: (handler: EventHandler, filter?: EventFilter) => Unsubscribe;
  clear: () => void;
  isAvailable: boolean;
  subscriberCount: number;
}

/**
 * React Native hook for PERS SDK event system
 * 
 * This hook provides access to the platform-agnostic event system for subscribing to
 * transaction, authentication, campaign, blockchain, and system events. All events 
 * include a `userMessage` field ready for display to end users.
 * 
 * **Event Domains:**
 * - `auth` - Authentication events (login, logout, token refresh)
 * - `user` - User profile events (update, create)
 * - `transaction` - Transaction events (created, submitted, confirmed)
 * - `campaign` - Campaign events (claimed, activated)
 * - `redemption` - Redemption events (redeemed, expired)
 * - `business` - Business events (created, updated, membership)
 * - `wallet` - Real-time blockchain events (Transfer, Approval, etc.) - Auto-enabled on auth
 * - `api` - API error events (network, validation, server errors)
 * 
 * **Blockchain Events (Wallet Domain):**
 * When `sdk.connectWalletEvents()` is called (or auto-enabled via `captureWalletEvents: true`),
 * real-time blockchain events are automatically routed through the same event system:
 * ```typescript
 * const { subscribe } = useEvents();
 * 
 * subscribe((event) => {
 *   if (event.domain === 'wallet') {
 *     console.log('Blockchain event:', event.type); // wallet_transfer, wallet_approval, etc.
 *   }
 * });
 * ```
 * 
 * **Notification Levels:**
 * - `success` - Operation completed successfully
 * - `error` - Operation failed
 * 
 * **Cleanup:**
 * All subscriptions created through this hook are automatically cleaned up when
 * the component unmounts, preventing memory leaks and stale event handlers.
 * 
 * @returns {EventsHook} Hook interface with event subscription methods
 * 
 * @example
 * **Basic Usage - Show All Notifications**
 * ```typescript
 * import { useEvents } from '@explorins/pers-sdk-react-native';
 * 
 * function NotificationComponent() {
 *   const { subscribe, isAvailable } = useEvents();
 *   
 *   useEffect(() => {
 *     if (!isAvailable) return;
 *     
 *     const unsubscribe = subscribe((event) => {
 *       // userMessage is always present and UI-ready
 *       showNotification(event.userMessage, event.level);
 *     });
 *     
 *     return () => unsubscribe();
 *   }, [subscribe, isAvailable]);
 *   
 *   return <View />;
 * }
 * ```
 * 
 * @example
 * **Filter by Domain and Level**
 * ```typescript
 * function TransactionListener() {
 *   const { subscribe, isAvailable } = useEvents();
 *   
 *   useEffect(() => {
 *     if (!isAvailable) return;
 *     
 *     // Only listen to successful transactions
 *     const unsubscribe = subscribe(
 *       (event) => {
 *         if (event.level === 'success') {
 *           playSuccessSound();
 *           showConfetti();
 *         }
 *       },
 *       { domain: 'transaction' }  // Filter
 *     );
 *     
 *     return () => unsubscribe();
 *   }, [subscribe, isAvailable]);
 * }
 * ```
 * 
 * @example
 * **Filter Errors for Logging**
 * ```typescript
 * function ErrorLogger() {
 *   const { subscribe, isAvailable } = useEvents();
 *   
 *   useEffect(() => {
 *     if (!isAvailable) return;
 *     
 *     const unsubscribe = subscribe(
 *       (event) => {
 *         // Log errors to crash reporting
 *         logToSentry({
 *           message: event.userMessage,
 *           domain: event.domain,
 *           type: event.type,
 *         });
 *       },
 *       { level: 'error' }  // Only errors
 *     );
 *     
 *     return () => unsubscribe();
 *   }, [subscribe, isAvailable]);
 * }
 * ```
 * 
 * @example
 * **One-time Event**
 * ```typescript
 * function FirstTransactionHandler() {
 *   const { once, isAvailable } = useEvents();
 *   
 *   useEffect(() => {
 *     if (!isAvailable) return;
 *     
 *     // Auto-unsubscribe after first transaction event
 *     const unsubscribe = once(
 *       (event) => {
 *         console.log('First transaction event:', event.type);
 *         showOnboardingComplete();
 *       },
 *       { domain: 'transaction', level: 'success' }
 *     );
 *     
 *     return () => unsubscribe();
 *   }, [once, isAvailable]);
 * }
 * ```
 * 
 * @example
 * **Combined Domain and Level Filter**
 * ```typescript
 * function AuthErrorHandler() {
 *   const { subscribe, isAvailable } = useEvents();
 *   
 *   useEffect(() => {
 *     if (!isAvailable) return;
 *     
 *     const unsubscribe = subscribe(
 *       (event) => {
 *         Alert.alert('Authentication Error', event.userMessage);
 *         navigation.navigate('Login');
 *       },
 *       { domain: 'auth', level: 'error' }
 *     );
 *     
 *     return () => unsubscribe();
 *   }, [subscribe, isAvailable]);
 * }
 * ```
 * 
 * @see {@link PersEvent} for event structure
 * @see {@link EventFilter} for filtering options
 * @see {@link EventHandler} for handler function type
 * 
 * @since 1.6.49
 */
export const useEvents = (): EventsHook => {
  const { sdk, isInitialized } = usePersSDK();
  
  // Track subscriptions for cleanup
  const subscriptionsRef = useRef<Unsubscribe[]>([]);
  
  // Cleanup all subscriptions on unmount
  useEffect(() => {
    return () => {
      subscriptionsRef.current.forEach(unsubscribe => {
        try {
          unsubscribe();
        } catch (e) {
          // Ignore cleanup errors
        }
      });
      subscriptionsRef.current = [];
    };
  }, []);

  /**
   * Subscribe to SDK events with optional filtering
   * 
   * Creates a subscription that will be called for every matching event.
   * The subscription is automatically tracked for cleanup when the component unmounts.
   * 
   * @param handler - Callback function invoked for each matching event
   * @param filter - Optional filter to limit events (by domain, level, or both)
   * @returns Unsubscribe function to manually cancel the subscription
   * 
   * @example
   * ```typescript
   * const unsubscribe = subscribe((event) => {
   *   console.log('Event:', event.type, event.userMessage);
   * });
   * 
   * // Later: manual cleanup
   * unsubscribe();
   * ```
   */
  const subscribe = useCallback((handler: EventHandler, filter?: EventFilter): Unsubscribe => {
    if (!isInitialized || !sdk) {
      console.warn('[useEvents] SDK not initialized. Cannot subscribe to events.');
      return () => {}; // Return no-op unsubscribe
    }
    
    const unsubscribe = sdk.events.subscribe(handler, filter);
    
    // Track for cleanup
    subscriptionsRef.current.push(unsubscribe);
    
    // Return wrapped unsubscribe that also removes from tracking
    return () => {
      unsubscribe();
      const index = subscriptionsRef.current.indexOf(unsubscribe);
      if (index > -1) {
        subscriptionsRef.current.splice(index, 1);
      }
    };
  }, [sdk, isInitialized]);

  /**
   * Subscribe to a single event (auto-unsubscribes after first match)
   * 
   * Useful for one-time event handling, like waiting for a specific action to complete.
   * 
   * @param handler - Callback function invoked for the first matching event
   * @param filter - Optional filter to limit events (by domain, level, or both)
   * @returns Unsubscribe function to manually cancel before event fires
   * 
   * @example
   * ```typescript
   * once((event) => {
   *   console.log('First event:', event.type);
   * }, { domain: 'transaction', level: 'success' });
   * ```
   */
  const once = useCallback((handler: EventHandler, filter?: EventFilter): Unsubscribe => {
    if (!isInitialized || !sdk) {
      console.warn('[useEvents] SDK not initialized. Cannot subscribe to events.');
      return () => {};
    }
    
    const unsubscribe = sdk.events.once(handler, filter);
    
    // Track for cleanup
    subscriptionsRef.current.push(unsubscribe);
    
    return () => {
      unsubscribe();
      const index = subscriptionsRef.current.indexOf(unsubscribe);
      if (index > -1) {
        subscriptionsRef.current.splice(index, 1);
      }
    };
  }, [sdk, isInitialized]);

  /**
   * Clear all event subscriptions from this hook instance
   * 
   * Useful when you want to reset all event listeners without unmounting the component.
   * Note: This only clears subscriptions created through this hook instance.
   * 
   * @example
   * ```typescript
   * const { clear, subscribe } = useEvents();
   * 
   * // Create some subscriptions
   * subscribe((event) => console.log(event));
   * subscribe((event) => logToServer(event));
   * 
   * // Later: clear all subscriptions from this hook
   * clear();
   * ```
   */
  const clear = useCallback((): void => {
    subscriptionsRef.current.forEach(unsubscribe => {
      try {
        unsubscribe();
      } catch (e) {
        // Ignore cleanup errors
      }
    });
    subscriptionsRef.current = [];
  }, []);

  /**
   * Get current subscriber count from the event emitter
   * 
   * Useful for debugging or showing active listener count in dev tools.
   */
  const subscriberCount = sdk?.events?.subscriberCount ?? 0;

  return {
    /**
     * Subscribe to SDK events with optional filtering
     * 
     * @param handler - Callback function for each matching event
     * @param filter - Optional filter by domain and/or level
     * @returns Unsubscribe function
     */
    subscribe,
    
    /**
     * Subscribe to a single event (auto-unsubscribes after first match)
     * 
     * @param handler - Callback function for the first matching event
     * @param filter - Optional filter by domain and/or level
     * @returns Unsubscribe function
     */
    once,
    
    /**
     * Clear all subscriptions created through this hook instance
     */
    clear,
    
    /**
     * Whether the event system is available
     * 
     * Returns `true` when SDK is initialized and events can be subscribed to.
     */
    isAvailable: isInitialized && !!sdk?.events,
    
    /**
     * Current number of active subscribers across all components
     * 
     * Useful for debugging event system usage.
     */
    subscriberCount,
  };
};

export type EventsHook_ = ReturnType<typeof useEvents>;
