/**
 * Dynamic Configuration Client Usage Examples
 * 
 * This example demonstrates how to use the Variably SDK's dynamic configuration
 * client with real-time updates and intelligent fallback to polling.
 */

import { 
  DynamicConfigClient, 
  DynamicConfigClientConfig,
  UserContext,
  DynamicConfigResult,
  ConfigChangeCallback
} from '../src/index';

// Example 1: Basic Usage with Real-time Updates
async function basicRealtimeExample() {
  console.log('=== Basic Real-time Dynamic Config Example ===');

  // Configuration for the client
  const config: DynamicConfigClientConfig = {
    apiKey: 'your-api-key-here',
    jwtToken: 'your-jwt-token-here', // Required for WebSocket authentication
    projectId: 'your-project-id',
    baseUrl: 'https://graphql.variably.tech',
    enableRealtime: true,
    debug: true
  };

  // Create client
  const configClient = new DynamicConfigClient(config);

  // User context for configuration evaluation
  const userContext: UserContext = {
    userId: 'user-123',
    email: 'user@example.com',
    country: 'US',
    attributes: {
      plan: 'premium',
      beta_user: true
    }
  };

  try {
    // Get a boolean configuration
    const featureEnabled = await configClient.getConfigBool(
      'new-dashboard-feature',
      false,
      userContext
    );
    console.log('New dashboard feature enabled:', featureEnabled);

    // Get a JSON configuration
    const themeConfig = await configClient.getConfigJSON(
      'ui-theme-config',
      { theme: 'light', primaryColor: '#007bff' },
      userContext
    );
    console.log('Theme configuration:', themeConfig);

    // Get a string configuration
    const apiEndpoint = await configClient.getConfigString(
      'api-endpoint',
      'https://api.example.com',
      userContext
    );
    console.log('API endpoint:', apiEndpoint);

    // Subscribe to real-time changes
    const unsubscribe = configClient.onConfigChange('new-dashboard-feature', (result) => {
      console.log('🔄 Configuration changed!', {
        key: result.key,
        newValue: result.value,
        version: result.version,
        realTime: result.realTimeUpdate
      });
    });

    // Simulate keeping the application running
    console.log('✅ Client setup complete. Listening for real-time updates...');
    
    // Clean up after 30 seconds (in real apps, this would be on app shutdown)
    setTimeout(() => {
      unsubscribe();
      configClient.disconnect();
      console.log('🔌 Client disconnected');
    }, 30000);

  } catch (error) {
    console.error('❌ Error:', error);
  }
}

// Example 2: Advanced Usage with Multiple Configurations
async function advancedExample() {
  console.log('\n=== Advanced Dynamic Config Example ===');

  const config: DynamicConfigClientConfig = {
    apiKey: process.env.VARIABLY_API_KEY || 'your-api-key',
    jwtToken: process.env.VARIABLY_JWT_TOKEN || 'your-jwt-token',
    projectId: process.env.VARIABLY_PROJECT_ID || 'your-project-id',
    baseUrl: process.env.VARIABLY_BASE_URL || 'https://graphql.variably.tech',
    enableRealtime: true,
    pollingInterval: 60000, // 60 second fallback polling
    cache: {
      ttl: 300000, // 5 minute cache
      maxSize: 500,
      enabled: true
    },
    debug: true
  };

  const configClient = new DynamicConfigClient(config);

  const userContext: UserContext = {
    userId: 'advanced-user-456',
    email: 'advanced@example.com',
    country: 'CA',
    platform: 'web',
    version: '2.1.0',
    attributes: {
      subscription: 'enterprise',
      feature_flags: ['beta', 'experimental']
    }
  };

  // Configuration keys we're interested in
  const configKeys = [
    'feature-limits',
    'pricing-model',
    'ui-customization',
    'integration-settings',
    'notification-preferences'
  ];

  try {
    // Get multiple configurations
    console.log('📋 Loading configurations...');
    
    const configurations = await Promise.all(
      configKeys.map(async (key) => {
        const result = await configClient.evaluateConfig(key, {}, userContext);
        return { key, result };
      })
    );

    configurations.forEach(({ key, result }) => {
      console.log(`  ✓ ${key}:`, {
        value: result.value,
        reason: result.reason,
        cached: result.cacheHit,
        version: result.version
      });
    });

    // Subscribe to all configuration changes
    const unsubscribeAll = configClient.onAnyConfigChange((result) => {
      console.log('🌐 Any config changed:', {
        key: result.key,
        value: result.value,
        updateType: result.realTimeUpdate ? 'real-time' : 'polling',
        version: result.version,
        timestamp: result.retrievedAt
      });
      
      // Handle specific configuration changes
      switch (result.key) {
        case 'feature-limits':
          console.log('  🔧 Updating feature limits in application...');
          break;
        case 'ui-customization':
          console.log('  🎨 Applying new UI customization...');
          break;
        case 'pricing-model':
          console.log('  💰 Updating pricing display...');
          break;
      }
    });

    // Monitor connection status
    const connectionStatus = configClient.getConnectionStatus();
    console.log('🔗 Connection status:', connectionStatus);

    // Refresh configurations manually if needed
    setTimeout(async () => {
      console.log('🔄 Manually refreshing configurations...');
      await configClient.refreshConfigs(userContext);
    }, 10000);

    // Clean up
    setTimeout(() => {
      unsubscribeAll();
      configClient.disconnect();
      console.log('🔌 Advanced client disconnected');
    }, 45000);

  } catch (error) {
    console.error('❌ Advanced example error:', error);
  }
}

// Example 3: Polling-Only Mode (for environments without WebSocket support)
async function pollingOnlyExample() {
  console.log('\n=== Polling-Only Mode Example ===');

  const config: DynamicConfigClientConfig = {
    apiKey: 'your-api-key',
    projectId: 'your-project-id',
    baseUrl: 'https://graphql.variably.tech',
    enableRealtime: false, // Disable real-time updates
    pollingInterval: 30000, // 30 second polling
    debug: true
  };

  const configClient = new DynamicConfigClient(config);

  const userContext: UserContext = {
    userId: 'polling-user-789',
    attributes: { environment: 'restricted-network' }
  };

  try {
    // Get configuration (will use polling for updates)
    const maintenanceMode = await configClient.getConfigBool(
      'maintenance-mode',
      false,
      userContext
    );
    console.log('Maintenance mode:', maintenanceMode);

    // Subscribe to changes (will be detected via polling)
    const unsubscribe = configClient.onConfigChange('maintenance-mode', (result) => {
      console.log('📊 Polling detected change:', {
        key: result.key,
        value: result.value,
        reason: result.reason
      });
    });

    console.log('✅ Polling-only client active. Checking for updates every 30 seconds...');

    // Clean up
    setTimeout(() => {
      unsubscribe();
      configClient.disconnect();
      console.log('🔌 Polling client disconnected');
    }, 120000);

  } catch (error) {
    console.error('❌ Polling example error:', error);
  }
}

// Example 4: Error Handling and Resilience
async function errorHandlingExample() {
  console.log('\n=== Error Handling Example ===');

  const config: DynamicConfigClientConfig = {
    apiKey: 'invalid-api-key', // Intentionally invalid
    jwtToken: 'invalid-jwt-token',
    projectId: 'test-project',
    baseUrl: 'https://graphql.variably.tech',
    enableRealtime: true,
    debug: true
  };

  const configClient = new DynamicConfigClient(config);

  const userContext: UserContext = {
    userId: 'error-test-user'
  };

  try {
    // This will fail due to invalid API key, but should return default value
    const result = await configClient.evaluateConfig(
      'test-config',
      'default-value',
      userContext
    );

    console.log('Result with error handling:', {
      value: result.value,
      reason: result.reason,
      hasError: !!result.error,
      errorMessage: result.error?.message
    });

    // The client should fall back to polling mode if WebSocket fails
    const status = configClient.getConnectionStatus();
    console.log('Connection status after error:', status);

  } catch (error) {
    console.error('❌ Unexpected error (should be handled gracefully):', error);
  }

  configClient.disconnect();
}

// Run examples
async function runExamples() {
  console.log('🚀 Starting Variably Dynamic Config SDK Examples\n');

  // Run examples in sequence
  await basicRealtimeExample();
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  await advancedExample();
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  await pollingOnlyExample();
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  await errorHandlingExample();

  console.log('\n✅ All examples completed!');
}

// Export examples for use in documentation or testing
export {
  basicRealtimeExample,
  advancedExample,
  pollingOnlyExample,
  errorHandlingExample,
  runExamples
};

// Run if this file is executed directly
if (require.main === module) {
  runExamples().catch(console.error);
}