/**
 * Advanced Usage Examples
 * 
 * This file demonstrates advanced patterns and use cases for the HANA Query API client,
 * including fluent API, request cancellation, parallel requests, and custom configurations.
 */

import { 
  HanaQueryClient,
  createClient,
  type Plan,
  type ItemStatus,
  type WorkOrder,
  isNotFoundError,
  isSuccessResponse
} from '../index.ts';

// ============================================================================
// Example 1: Fluent Request Builder API
// ============================================================================

async function fluentRequestBuilder() {
  console.log('=== Fluent Request Builder API ===');
  
  const client = new HanaQueryClient({ baseUrl: 'http://localhost:3001' });
  
  try {
    // Using fluent API for complex requests
    console.log('Building complex requests with fluent API...');
    
    // Simple fluent request
    const health = await client
      .request('/health')
      .timeout(5000)
      .execute();
    
      if (isSuccessResponse(health)) {
    console.log(`✅ Health check via fluent API: ${health.data.status}`);
      } else {
        console.log(`❌ Health check via fluent API: ${health.problem.detail}`);
      }
    
    // Fluent request with query parameters
    const items = await client
      .request('/items/status')
      .query({
        from: '2025-01-01',
        to: '2025-06-30'
      })
      .timeout(60000) // Longer timeout for large dataset
      .retries(5)     // More retries for important data
      .execute();
    
    if (isSuccessResponse(items)) {
      console.log(`✅ Items via fluent API: ${items.metadata.count} items found`);
    } else {
      console.log(`❌ Items via fluent API: ${items.problem.detail}`);
    }
    
    // Multiple fluent requests with different configurations
    const planIds = [1, 2, 3];
    const planRequests = planIds.map(planId =>
      client
        .request(`/plans/${planId}`)
        .timeout(10000)
        .retries(2)
        .execute()
        .catch(error => ({ error, planId }))
    );
    
    const planResults = await Promise.all(planRequests);
    
    console.log('\\nPlan requests results:');
    planResults.forEach((result, index) => {
      if ('error' in result) {
        const errorMsg = result.error instanceof Error ? result.error.message : String(result.error);
        console.log(`  Plan ${result.planId}: ❌ ${errorMsg}`);
      } else if (isSuccessResponse(result)) {
        console.log(`  Plan ${planIds[index]}: ✅ ${result.data.plan_status}`);
      } else {
        console.log(`  Plan ${planIds[index]}: ❌ Error response received`);
      }
    });
    
  } catch (error: unknown) {
    if (error instanceof Error) {
      console.error('Error in fluent API example:', error instanceof Error ? error.message : String(error));
    } else {
      console.error('Error in fluent API example:', error);
    }
  }
}

// ============================================================================
// Example 2: Request Cancellation and Timeouts
// ============================================================================

async function requestCancellationAndTimeouts() {
  console.log('\\n=== Request Cancellation and Timeouts ===');
  
  const client = new HanaQueryClient({ baseUrl: 'http://localhost:3001' });
  
  // Example 1: Manual request cancellation
  console.log('Testing manual request cancellation...');
  
  const controller = new AbortController();
  
  // Start a request that we'll cancel
  const promise = client.getItemHierarchies({
    signal: controller.signal,
    timeout: 30000
  });
  
  // Cancel the request after 2 seconds
  setTimeout(() => {
    console.log('⏹️ Cancelling request after 2 seconds...');
    controller.abort();
  }, 2000);
  
  try {
    await promise;
    console.log('✅ Request completed before cancellation');
  } catch (error: unknown) {
    if (error instanceof Error) {
      if (error.name === 'AbortError' || error.message.includes('abort')) {
        console.log('✅ Request successfully cancelled');
      } else {
        console.log('❌ Request failed for other reason:', error.message);
      }
    } else {
      console.log('❌ Request failed for unknown reason:', error);
    }
  }
  
  // Example 2: Racing requests with timeout
  console.log('\\nTesting request racing with timeout...');
  
  async function raceWithTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {
    const timeoutPromise = new Promise<never>((_, reject) => {
      setTimeout(() => reject(new Error(`Operation timed out after ${timeoutMs}ms`)), timeoutMs);
    });
    
    return Promise.race([promise, timeoutPromise]);
  }
  
  try {
    const quickResult = await raceWithTimeout(
      client.getHealth(),
      5000 // 5 second timeout
    );
    console.log('✅ Quick request completed:', quickResult.data.status);
  } catch (error: unknown) {
    if (error instanceof Error) {
      console.log('❌ Request timed out:', error instanceof Error ? error.message : String(error));
    } else {
      console.log('❌ Request timed out:', error);
    }
  }
  
  // Example 3: Timeout configuration per endpoint type
  console.log('\\nTesting endpoint-specific timeouts...');
  
  const timeoutConfigs = {
    health: 5000,      // Fast endpoint
    plans: 15000,      // Medium endpoint
    items: 60000,      // Slow endpoint with large data
    hierarchies: 90000 // Slowest endpoint
  };
  
  try {
    const [health, plans] = await Promise.all([
      client.getHealth({ timeout: timeoutConfigs.health }),
      client.getPlans({ timeout: timeoutConfigs.plans })
    ]);
    
    console.log(`✅ Health (${timeoutConfigs.health}ms): ${health.data.status}`);
    console.log(`✅ Plans (${timeoutConfigs.plans}ms): ${plans.metadata.count} plans`);
    
  } catch (error: unknown) {
    if (error instanceof Error) {
      console.log('❌ Timeout configuration test failed:', error instanceof Error ? error.message : String(error));
    } else {
      console.log('❌ Timeout configuration test failed:', error);
    }
  }
}

// ============================================================================
// Example 3: Parallel and Batch Operations
// ============================================================================

async function parallelAndBatchOperations() {
  console.log('\\n=== Parallel and Batch Operations ===');
  
  const client = new HanaQueryClient({ baseUrl: 'http://localhost:3001' });
  
  // Example 1: Parallel independent requests
  console.log('Running parallel independent requests...');
  
  const startTime = Date.now();
  
  try {
    const [health, docs, plans, hierarchies] = await Promise.allSettled([
      client.getHealth(),
      client.getDocs(),
      client.getPlans(),
      client.getItemHierarchies()
    ]);
    
    const duration = Date.now() - startTime;
    console.log(`✅ Parallel requests completed in ${duration}ms`);
    
    // Process results
    if (health.status === 'fulfilled') {
      console.log(`  Health: ✅ ${health.value.data.status}`);
    } else {
      console.log(`  Health: ❌ ${health.reason.message}`);
    }
    
    if (docs.status === 'fulfilled') {
      console.log(`  Docs: ✅ ${docs.value.data.name} v${docs.value.data.version}`);
    } else {
      console.log(`  Docs: ❌ ${docs.reason.message}`);
    }
    
    if (plans.status === 'fulfilled') {
      console.log(`  Plans: ✅ ${plans.value.metadata.count} plans`);
    } else {
      console.log(`  Plans: ❌ ${plans.reason.message}`);
    }
    
    if (hierarchies.status === 'fulfilled') {
      console.log(`  Hierarchies: ✅ ${hierarchies.value.metadata.count} relationships`);
    } else {
      console.log(`  Hierarchies: ❌ ${hierarchies.reason.message}`);
    }
    
  } catch (error: unknown) {
    console.error('Parallel requests failed:', error instanceof Error ? error.message : String(error));
  }
  
  // Example 2: Batch processing with controlled concurrency
  console.log('\\nTesting controlled concurrency batch processing...');
  
  async function processBatch<T, R>(
    items: T[],
    processor: (item: T) => Promise<R>,
    batchSize: number = 3
  ): Promise<R[]> {
    const results: R[] = [];
    
    for (let i = 0; i < items.length; i += batchSize) {
      const batch = items.slice(i, i + batchSize);
      console.log(`  Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(items.length / batchSize)}`);
      
      const batchResults = await Promise.allSettled(
        batch.map(processor)
      );
      
      for (const result of batchResults) {
        if (result.status === 'fulfilled') {
          results.push(result.value);
        } else {
          console.log(`    ❌ Batch item failed: ${result.reason.message}`);
        }
      }
    }
    
    return results;
  }
  
  try {
    // Get plan IDs first
    const plansResponse = await client.getPlans();
    const planIds = plansResponse.data.plans.map(p => p.plan_id).slice(0, 6); // Limit for demo
    
    // Process plans in batches
    const planDetails = await processBatch(
      planIds,
      async (planId) => {
        const plan = await client.getPlan(planId);
        return { planId, plan: plan.data.plan };
      },
      2 // Process 2 plans at a time
    );
    
    console.log(`✅ Processed ${planDetails.length} plans in batches`);
    
  } catch (error: unknown) {
    console.error('Batch processing failed:', error instanceof Error ? error.message : String(error));
  }
  
  // Example 3: Data aggregation from multiple endpoints
  console.log('\\nAggregating data from multiple endpoints...');
  
  try {
    const aggregatedData = await client.getPlans().then(async (plansResponse) => {
      const plans = plansResponse.data.plans.slice(0, 3); // Limit for demo
      
      // Get detailed data for each plan
      const planDataPromises = plans.map(async (plan) => {
        const [productsResult, workOrdersResult] = await Promise.allSettled([
          client.getPlanProducts(plan.plan_id),
          client.getPlanWorkOrders(plan.plan_id)
        ]);
        
        return {
          plan,
          products: productsResult.status === 'fulfilled' ? productsResult.value.data.products : [],
          workOrders: workOrdersResult.status === 'fulfilled' ? workOrdersResult.value.data.workOrders : [],
          hasProducts: productsResult.status === 'fulfilled',
          hasWorkOrders: workOrdersResult.status === 'fulfilled'
        };
      });
      
      return Promise.all(planDataPromises);
    });
    
    console.log(`✅ Aggregated data for ${aggregatedData.length} plans:`);
    aggregatedData.forEach(data => {
      console.log(`  Plan ${data.plan.plan_id}: ${data.products.length} products, ${data.workOrders.length} work orders`);
    });
    
  } catch (error: unknown) {
    console.error('Data aggregation failed:', error instanceof Error ? error.message : String(error));
  }
}

// ============================================================================
// Example 4: Custom Client Configurations
// ============================================================================

async function customClientConfigurations() {
  console.log('\\n=== Custom Client Configurations ===');
  
  // Example 1: High-performance client for bulk operations
  const bulkClient = createClient({
    baseUrl: 'http://localhost:3001'
  }, {
    timeout: 120000,      // 2 minutes for large datasets
    retries: 5,           // More retries for important operations
    retryDelay: 2000,     // Longer delay between retries
    enableLogging: true,
    logLevel: 'info',
    headers: {
      'X-Client-Type': 'bulk-operations',
      'X-Request-Priority': 'high'
    }
  });
  
  console.log('Created high-performance bulk client');
  
  // Example 2: Quick client for real-time operations
  const quickClient = createClient({
    baseUrl: 'http://localhost:3001'
  }, {
    timeout: 5000,        // Quick timeout
    retries: 1,           // Minimal retries
    retryDelay: 500,      // Fast retry
    enableLogging: false, // No logging for performance
    headers: {
      'X-Client-Type': 'real-time',
      'X-Request-Priority': 'urgent'
    }
  });
  
  console.log('Created quick real-time client');
  
  // Example 3: Debug client with extensive logging
  const debugClient = createClient({
    baseUrl: 'http://localhost:3001'
  }, {
    enableLogging: true,
    logLevel: 'debug',
    timeout: 30000,
    retries: 0, // No retries to see all failures
    headers: {
      'X-Client-Type': 'debug',
      'X-Debug-Mode': 'enabled'
    }
  });
  
  console.log('Created debug client with extensive logging');
  
  // Test the different clients
  try {
    console.log('\\nTesting different client configurations...');
    
    // Quick health checks with different clients
    const [bulkHealth, quickHealth, debugHealth] = await Promise.allSettled([
      bulkClient.getHealth(),
      quickClient.getHealth(),
      debugClient.getHealth()
    ]);
    
    console.log('Client test results:');
    console.log(`  Bulk client: ${bulkHealth.status === 'fulfilled' ? '✅' : '❌'}`);
    console.log(`  Quick client: ${quickHealth.status === 'fulfilled' ? '✅' : '❌'}`);
    console.log(`  Debug client: ${debugHealth.status === 'fulfilled' ? '✅' : '❌'}`);
    
    // Demonstrate configuration updates
    console.log('\\nUpdating client configuration dynamically...');
    
    quickClient.updateConfig({
      timeout: 10000,  // Increase timeout
      enableLogging: true,
      logLevel: 'warn'
    });
    
    console.log('✅ Quick client configuration updated');
    
    // Show current configuration
    const config = quickClient.getConfig();
    console.log(`Updated timeout: ${config.timeout}ms`);
    console.log(`Logging enabled: ${config.enableLogging}`);
    
  } catch (error: unknown) {
    console.error('Client configuration test failed:', error instanceof Error ? error.message : String(error));
  }
}

// ============================================================================
// Example 5: Advanced Data Processing Patterns
// ============================================================================

async function advancedDataProcessing() {
  console.log('\\n=== Advanced Data Processing Patterns ===');
  
  const client = new HanaQueryClient({ baseUrl: 'http://localhost:3001' });
  
  // Example 1: Streaming-like data processing
  console.log('Implementing streaming-like data processing...');
  
  async function* processItemsInChunks(chunkSize: number = 1000) {
    try {
      const items = await client.getItems();
      const allItems = items.data.items;
      
      for (let i = 0; i < allItems.length; i += chunkSize) {
        const chunk = allItems.slice(i, i + chunkSize);
        yield {
          chunk,
          chunkIndex: Math.floor(i / chunkSize),
          totalChunks: Math.ceil(allItems.length / chunkSize),
          itemsInChunk: chunk.length,
          totalItems: allItems.length
        };
      }
    } catch (error: unknown) {
      throw error;
    }
  }
  
  try {
    console.log('Processing items in chunks...');
    let processedCount = 0;
    
    for await (const { chunk, chunkIndex, totalChunks, itemsInChunk } of processItemsInChunks(500)) {
      // Process each chunk
      const lowStockInChunk = chunk.filter((item: any) => item.onhand < item.min);
      processedCount += itemsInChunk;
      
      console.log(`  Chunk ${chunkIndex + 1}/${totalChunks}: ${itemsInChunk} items, ${lowStockInChunk.length} low stock`);
      
      // Simulate processing delay
      await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    console.log(`✅ Processed ${processedCount} items in chunks`);
    
  } catch (error: unknown) {
    console.error('Chunk processing failed:', error instanceof Error ? error.message : String(error));
  }
  
  // Example 2: Complex data transformation pipeline
  console.log('\\nImplementing data transformation pipeline...');
  
  interface PlanAnalysis {
    plan: Plan;
    efficiency: number;
    status: 'excellent' | 'good' | 'needs_attention' | 'critical';
    products: number;
    workOrders: number;
    completionRate: number;
  }
  
  async function analyzePlanEfficiency(): Promise<PlanAnalysis[]> {
    const plans = await client.getPlans();
    
    const analyses = await Promise.allSettled(
      plans.data.plans.map(async (plan): Promise<PlanAnalysis> => {
        const [productsResult, workOrdersResult] = await Promise.allSettled([
          client.getPlanProducts(plan.plan_id),
          client.getPlanWorkOrders(plan.plan_id)
        ]);
        
        const products = productsResult.status === 'fulfilled' ? productsResult.value.data.products.length : 0;
        const workOrders = workOrdersResult.status === 'fulfilled' ? workOrdersResult.value.data.workOrders : [];
        
        // Calculate efficiency metrics
        const totalPlanned = workOrders.reduce((sum, wo) => sum + wo.order_plannedqty, 0);
        const totalCompleted = workOrders.reduce((sum, wo) => sum + wo.order_completedqty, 0);
        const completionRate = totalPlanned > 0 ? (totalCompleted / totalPlanned) : 0;
        
        const efficiency = plan.products_total > 0 
          ? (plan.products_closed / plan.products_total) * 100 
          : 0;
        
        let status: PlanAnalysis['status'];
        if (efficiency >= 90) status = 'excellent';
        else if (efficiency >= 70) status = 'good';
        else if (efficiency >= 50) status = 'needs_attention';
        else status = 'critical';
        
        return {
          plan,
          efficiency,
          status,
          products,
          workOrders: workOrders.length,
          completionRate: completionRate * 100
        };
      })
    );
    
    return analyses
      .filter((result): result is PromiseFulfilledResult<PlanAnalysis> => result.status === 'fulfilled')
      .map(result => result.value);
  }
  
  try {
    const analyses = await analyzePlanEfficiency();
    
    console.log(`✅ Analyzed ${analyses.length} plans:`);
    
    // Group by status
    const statusGroups = analyses.reduce((groups, analysis) => {
      if (!groups[analysis.status]) groups[analysis.status] = [];
      groups[analysis.status].push(analysis);
      return groups;
    }, {} as Record<string, PlanAnalysis[]>);
    
    Object.entries(statusGroups).forEach(([status, group]) => {
      console.log(`  ${status.toUpperCase()}: ${group.length} plans`);
      group.forEach(analysis => {
        console.log(`    Plan ${analysis.plan.plan_id}: ${analysis.efficiency.toFixed(1)}% efficiency`);
      });
    });
    
  } catch (error: unknown) {
    console.error('Plan analysis failed:', error instanceof Error ? error.message : String(error));
  }
  
  // Example 3: Real-time data monitoring simulation
  console.log('\\nSimulating real-time data monitoring...');
  
  async function monitorApiHealth(intervalMs: number = 5000, duration: number = 20000) {
    console.log(`Starting health monitoring (${duration / 1000}s duration, ${intervalMs / 1000}s interval)...`);
    
    const startTime = Date.now();
    let checkCount = 0;
    const healthHistory: Array<{ timestamp: number; status: string; uptime: number; responseTime: number }> = [];
    
    const monitoringInterval = setInterval(async () => {
      try {
        const requestStart = Date.now();
        const health = await client.getHealth({ timeout: 3000 });
        const responseTime = Date.now() - requestStart;
        
        checkCount++;
        healthHistory.push({
          timestamp: Date.now(),
          status: health.data.status,
          uptime: health.data.uptime,
          responseTime
        });
        
        console.log(`  Check ${checkCount}: ${health.data.status} (${responseTime}ms)`);
        
      } catch (error: unknown) {
        console.log(`  Check ${++checkCount}: ❌ ${error instanceof Error ? error.message : String(error)}`);
        healthHistory.push({
          timestamp: Date.now(),
          status: 'error',
          uptime: 0,
          responseTime: 0
        });
      }
      
      // Stop after duration
      if (Date.now() - startTime >= duration) {
        clearInterval(monitoringInterval);
        
        // Summary
        const avgResponseTime = healthHistory
          .filter(h => h.status === 'ok')
          .reduce((sum, h, _, arr) => sum + h.responseTime / arr.length, 0);
        
        const successRate = (healthHistory.filter(h => h.status === 'ok').length / healthHistory.length) * 100;
        
        console.log(`✅ Monitoring complete:`);
        console.log(`  Total checks: ${checkCount}`);
        console.log(`  Success rate: ${successRate.toFixed(1)}%`);
        console.log(`  Average response time: ${avgResponseTime.toFixed(1)}ms`);
      }
    }, intervalMs);
  }
  
  try {
    await monitorApiHealth(3000, 15000); // 15 seconds, check every 3 seconds
  } catch (error: unknown) {
    console.error('Health monitoring failed:', error instanceof Error ? error.message : String(error));
  }
}

// ============================================================================
// Main Execution
// ============================================================================

async function runAdvancedUsageExamples() {
  console.log('🚀 HANA Query API Client - Advanced Usage Examples');
  console.log('='.repeat(60));
  
  try {
    await fluentRequestBuilder();
    await requestCancellationAndTimeouts();
    await parallelAndBatchOperations();
    await customClientConfigurations();
    await advancedDataProcessing();
    
    console.log('\\n✅ All advanced usage examples completed!');
    
  } catch (error: unknown) {
    console.error('\\n❌ Advanced usage examples failed:', error);
  }
}

// Run examples if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
  runAdvancedUsageExamples().catch(console.error);
}

export {
  fluentRequestBuilder,
  requestCancellationAndTimeouts,
  parallelAndBatchOperations,
  customClientConfigurations,
  advancedDataProcessing,
  runAdvancedUsageExamples
};