/**
 * MemoryStack Provider Component
 * Wrap your app with this to enable MemoryStack hooks
 */

import React, { useEffect, useState, useCallback, useMemo, ReactNode } from 'react';
import { MemoryStackClient } from '../client';
import { MemoryStackContext, MemoryStackContextValue } from './MemoryStackContext';
import type { MemoryStackConfig } from '../types';

export interface MemoryStackProviderProps {
    /** Children components */
    children: ReactNode;
    /** MemoryStack configuration */
    config: MemoryStackConfig;
    /**
     * Optional AsyncStorage instance for offline support
     * Pass @react-native-async-storage/async-storage
     */
    storage?: {
        getItem: (key: string) => Promise<string | null>;
        setItem: (key: string, value: string) => Promise<void>;
        removeItem: (key: string) => Promise<void>;
    };
    /**
     * Optional NetInfo instance for network detection
     * Pass @react-native-community/netinfo
     */
    netInfo?: {
        fetch: () => Promise<{ isConnected: boolean | null; isInternetReachable: boolean | null }>;
        addEventListener: (callback: (state: { isConnected: boolean | null }) => void) => () => void;
    };
}

/**
 * MemoryStack Provider
 * 
 * @example
 * ```tsx
 * import AsyncStorage from '@react-native-async-storage/async-storage';
 * import NetInfo from '@react-native-community/netinfo';
 * 
 * function App() {
 *   return (
 *     <MemoryStackProvider
 *       config={{ apiKey: 'ms_...', enableOffline: true }}
 *       storage={AsyncStorage}
 *       netInfo={NetInfo}
 *     >
 *       <YourApp />
 *     </MemoryStackProvider>
 *   );
 * }
 * ```
 */
export function MemoryStackProvider({
    children,
    config,
    storage,
    netInfo,
}: MemoryStackProviderProps): React.ReactElement {
    const [client, setClient] = useState<MemoryStackClient | null>(null);
    const [isOnline, setIsOnline] = useState(true);
    const [pendingOperations, setPendingOperations] = useState(0);
    const [isInitialized, setIsInitialized] = useState(false);

    // Initialize client
    useEffect(() => {
        const newClient = new MemoryStackClient(config);

        // Set up storage if provided
        if (storage) {
            newClient.setStorage(storage);
        }

        // Set up network provider if provided
        if (netInfo) {
            newClient.setNetworkProvider({
                isConnected: async () => {
                    const state = await netInfo.fetch();
                    return state.isConnected ?? true;
                },
                addEventListener: (callback) => {
                    return netInfo.addEventListener((state) => {
                        callback(state.isConnected ?? true);
                    });
                },
            });

            // Get initial network state
            netInfo.fetch().then((state) => {
                setIsOnline(state.isConnected ?? true);
            });

            // Subscribe to network changes
            const unsubscribe = netInfo.addEventListener((state) => {
                setIsOnline(state.isConnected ?? true);
            });

            setClient(newClient);
            setIsInitialized(true);

            return () => {
                unsubscribe();
            };
        }

        setClient(newClient);
        setIsInitialized(true);

        return undefined;
    }, [config.apiKey, config.baseUrl]);

    // Update pending operations count
    useEffect(() => {
        if (!client || !config.enableOffline) return;

        const updatePendingCount = async () => {
            try {
                const status = await client.getPendingOperations();
                setPendingOperations(status.pendingCount);
            } catch {
                // Ignore errors
            }
        };

        // Check immediately
        updatePendingCount();

        // Poll every 5 seconds
        const interval = setInterval(updatePendingCount, 5000);

        return () => clearInterval(interval);
    }, [client, config.enableOffline]);

    // Sync pending operations
    const syncPending = useCallback(async () => {
        if (!client) return;

        try {
            const result = await client.processPendingOperations();
            setPendingOperations(result.remaining);
        } catch (error) {
            console.error('[MemoryStack] Failed to sync pending operations:', error);
        }
    }, [client]);

    // Memoize context value
    const contextValue = useMemo<MemoryStackContextValue>(
        () => ({
            client,
            isOnline,
            pendingOperations,
            syncPending,
            isInitialized,
        }),
        [client, isOnline, pendingOperations, syncPending, isInitialized]
    );

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

export default MemoryStackProvider;
