/**
 * Error Handling Examples
 * 
 * This file demonstrates comprehensive error handling strategies
 * for the HANA Query API client.
 */

import { 
  HanaQueryClient,
  HanaQueryClientError,
  NetworkError,
  TimeoutError,
  ValidationError,
  AuthorizationError,
  NotFoundError,
  ServerError,
  UnknownError,
  isRetryableError,
  getRetryDelay,
  isNetworkError,
  isTimeoutError,
  isValidationError,
  isNotFoundError,
  isServerError
} from '../index.ts';

// ============================================================================
// Example 1: Basic Error Handling
// ============================================================================

async function basicErrorHandling() {
  console.log('=== Basic Error Handling ===');
  
  const client = new HanaQueryClient({ baseUrl: 'http://localhost:3001' });
  
  try {
    // This will succeed if API is available
    const health = await client.getHealth();
    console.log('✅ Health check successful:', health.data.status);
    
  } catch (error: unknown) {
    // Handle any errors
    if (error instanceof HanaQueryClientError) {
      console.error('❌ API Error:', {
        type: error.type,
        message: error instanceof Error ? error.message : String(error),
        statusCode: error.statusCode
      });
    } else {
      console.error('❌ Unexpected Error:', error);
    }
  }
}

// ============================================================================
// Example 2: Specific Error Type Handling
// ============================================================================

async function specificErrorHandling() {
  console.log('\\n=== Specific Error Type Handling ===');
  
  const client = new HanaQueryClient({
    baseUrl: 'http://invalid-url-that-does-not-exist.com', // This will cause network errors
    timeout: 1000 // Very short timeout to trigger timeout errors
  });
  
  try {
    console.log('Attempting request with invalid URL...');
    await client.getHealth();
    
  } catch (error: unknown) {
    if (error instanceof NetworkError) {
      console.log('🌐 Network Error detected:');
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
      console.log(`  Original error: ${error.originalError?.message}`);
      
    } else if (error instanceof TimeoutError) {
      console.log('⏱️ Timeout Error detected:');
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
      console.log(`  Duration: ${error.context?.duration}ms`);
      
    } else if (error instanceof ValidationError) {
      console.log('✏️ Validation Error detected:');
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
      
    } else if (error instanceof AuthorizationError) {
      console.log('🔒 Authorization Error detected:');
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
      console.log(`  Status Code: ${error.statusCode}`);
      
    } else if (error instanceof NotFoundError) {
      console.log('🔍 Not Found Error detected:');
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
      console.log(`  Resource: ${error.context?.url}`);
      
    } else if (error instanceof ServerError) {
      console.log('🔥 Server Error detected:');
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
      console.log(`  Status Code: ${error.statusCode}`);
      console.log(`  Problem Details:`, error.problemDetails);
      
    } else {
      console.log('❓ Unknown Error:');
      console.log(`  Type: ${error && typeof error === 'object' && 'constructor' in error ? error.constructor.name : 'Unknown'}`);
      console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
    }
  }
}

// ============================================================================
// Example 3: Error Type Guards
// ============================================================================

async function errorTypeGuards() {
  console.log('\\n=== Error Type Guards ===');
  
  const client = new HanaQueryClient({
    baseUrl: 'http://localhost:99999', // Non-existent port
    timeout: 2000
  });
  
  try {
    await client.getPlans();
    
  } catch (error: unknown) {
    console.log('Error caught, analyzing with type guards:');
    
    if (isNetworkError(error)) {
      console.log('🌐 Type guard confirmed: Network Error');
      console.log(`  Can retry: ${isRetryableError(error)}`);
      
    } else if (isTimeoutError(error)) {
      console.log('⏱️ Type guard confirmed: Timeout Error');
      console.log(`  Can retry: ${isRetryableError(error)}`);
      
    } else if (isValidationError(error)) {
      console.log('✏️ Type guard confirmed: Validation Error');
      console.log(`  Can retry: ${isRetryableError(error)}`);
      
    } else if (isNotFoundError(error)) {
      console.log('🔍 Type guard confirmed: Not Found Error');
      console.log(`  Can retry: ${isRetryableError(error)}`);
      
    } else if (isServerError(error)) {
      console.log('🔥 Type guard confirmed: Server Error');
      console.log(`  Can retry: ${isRetryableError(error)}`);
      
    } else {
      console.log('❓ Type guard: Unknown error type');
    }
  }
}

// ============================================================================
// Example 4: Graceful Error Handling for Expected Scenarios
// ============================================================================

async function gracefulErrorHandling() {
  console.log('\\n=== Graceful Error Handling ===');
  
  const client = new HanaQueryClient({ baseUrl: 'http://localhost:3001' });
  
  // Function to safely get plan work orders (which may not exist)
  async function safeGetPlanWorkOrders(planId: number | string) {
    try {
      const workOrders = await client.getPlanWorkOrders(planId);
      return {
        success: true,
        data: workOrders.data.workOrders,
        count: workOrders.metadata.count
      };
    } catch (error: unknown) {
      if (isNotFoundError(error)) {
        // This is expected for plans without work orders
        return {
          success: true,
          data: [],
          count: 0,
          note: 'No work orders found for this plan'
        };
      } else {
        // Unexpected error
        return {
          success: false,
          error: error instanceof Error ? error.message : String(error)
        };
      }
    }
  }
  
  try {
    // Get plans first
    const plans = await client.getPlans();
    const firstPlanId = plans.data.plans[0]?.plan_id;
    
    if (firstPlanId) {
      console.log(`Checking work orders for plan ${firstPlanId}...`);
      
      const result = await safeGetPlanWorkOrders(firstPlanId);
      
      if (result.success) {
        console.log(`✅ Found ${result.count} work orders`);
        if (result.note) {
          console.log(`  Note: ${result.note}`);
        }
      } else {
        console.log(`❌ Failed to get work orders: ${result.error}`);
      }
    }
    
  } catch (error: unknown) {
    console.error('Error in graceful handling example:', error instanceof Error ? error.message : String(error));
  }
}

// ============================================================================
// Example 5: Custom Retry Logic
// ============================================================================

async function customRetryLogic() {
  console.log('\\n=== Custom Retry Logic ===');
  
  const client = new HanaQueryClient({
    baseUrl: 'http://localhost:3001',
    retries: 0 // Disable built-in retries for this example
  });
  
  async function retryableOperation<T>(
    operation: () => Promise<T>,
    maxRetries: number = 3,
    baseDelay: number = 1000
  ): Promise<T> {
    let lastError: HanaQueryClientError | null = null;
    
    for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
      try {
        console.log(`  Attempt ${attempt}/${maxRetries + 1}`);
        const result = await operation();
        
        if (attempt > 1) {
          console.log(`  ✅ Success on attempt ${attempt}`);
        }
        
        return result;
        
      } catch (error: unknown) {
        if (error instanceof HanaQueryClientError) {
          lastError = error;
          
          console.log(`  ❌ Attempt ${attempt} failed: ${error.type} - ${error instanceof Error ? error.message : String(error)}`);
          
          // Check if error is retryable
          if (!isRetryableError(error)) {
            console.log(`  🚫 Error is not retryable, stopping`);
            break;
          }
          
          // Don't wait after the last attempt
          if (attempt <= maxRetries) {
            const delay = getRetryDelay(attempt, baseDelay, 10000);
            console.log(`  ⏳ Waiting ${delay}ms before retry...`);
            await new Promise(resolve => setTimeout(resolve, delay));
          }
        } else {
          throw error; // Re-throw unexpected errors
        }
      }
    }
    
    throw lastError!;
  }
  
  try {
    console.log('Testing custom retry logic with network error...');
    
    // This will fail but demonstrate retry logic
    const invalidClient = new HanaQueryClient({
      baseUrl: 'http://localhost:99999',
      retries: 0
    });
    
    await retryableOperation(
      () => invalidClient.getHealth(),
      3, // 3 retries
      500 // 500ms base delay
    );
    
  } catch (error: unknown) {
    console.log(`Final error after all retries: ${error instanceof Error ? error.message : String(error)}`);
  }
}

// ============================================================================
// Example 6: Error Context and Debugging
// ============================================================================

async function errorContextAndDebugging() {
  console.log('\\n=== Error Context and Debugging ===');
  
  const client = new HanaQueryClient({
    baseUrl: 'http://localhost:3001',
    enableLogging: true,
    logLevel: 'debug'
  });
  
  // Function to log detailed error information
  function logErrorDetails(error: HanaQueryClientError) {
    console.log('🔍 Detailed Error Analysis:');
    console.log(`  Type: ${error.type}`);
    console.log(`  Message: ${error instanceof Error ? error.message : String(error)}`);
    console.log(`  Status Code: ${error.statusCode || 'N/A'}`);
    
    if (error.context) {
      console.log('  Request Context:');
      console.log(`    Method: ${error.context.method}`);
      console.log(`    URL: ${error.context.url}`);
      console.log(`    Duration: ${error.context.duration || 'N/A'}ms`);
      console.log(`    Attempt: ${error.context.attempt || 'N/A'}/${error.context.maxAttempts || 'N/A'}`);
    }
    
    if (error.problemDetails) {
      console.log('  Problem Details:');
      console.log(`    Title: ${error.problemDetails.title}`);
      console.log(`    Detail: ${error.problemDetails.detail}`);
      console.log(`    Instance: ${error.problemDetails.instance}`);
      if (error.problemDetails.issues.length > 0) {
        console.log(`    Issues: ${error.problemDetails.issues.join(', ')}`);
      }
    }
    
    if (error.originalError) {
      console.log(`  Original Error: ${error.originalError.message}`);
    }
    
    // Error serialization for logging
    console.log('  JSON Representation:', JSON.stringify(error.toJSON(), null, 2));
  }
  
  try {
    // Test with invalid parameters to trigger validation error
    await client.getSales({
      from: 'invalid-date',
      to: 'also-invalid'
    } as any);
    
  } catch (error: unknown) {
    if (error instanceof HanaQueryClientError) {
      logErrorDetails(error);
    }
  }
}

// ============================================================================
// Example 7: Production-Ready Error Handling Strategy
// ============================================================================

class RobustAPIService {
  private client: HanaQueryClient;
  private config: {
    baseUrl: string;
    enableLogging?: boolean;
    logLevel?: 'debug' | 'info' | 'warn' | 'error';
    timeout?: number;
    retries?: number;
  };
  
  constructor(config: {
    baseUrl: string;
    enableLogging?: boolean;
    logLevel?: 'debug' | 'info' | 'warn' | 'error';
    timeout?: number;
    retries?: number;
  }) {
    this.config = config;
    this.client = new HanaQueryClient({
      baseUrl: config.baseUrl,
      enableLogging: config.enableLogging ?? false,
      logLevel: config.logLevel ?? 'error',
      timeout: config.timeout ?? 30000,
      retries: config.retries ?? 3
    });
  }
  
  /**
   * Wrapper method that handles errors consistently
   */
  private async safeApiCall<T>(
    operation: () => Promise<T>,
    fallbackValue?: T
  ): Promise<{ success: true; data: T } | { success: false; error: string; type: string }> {
    try {
      const data = await operation();
      return { success: true, data };
      
    } catch (error: unknown) {
      if (error instanceof HanaQueryClientError) {
        // Log error details if logging is enabled
        if (this.config.enableLogging) {
          console.error('API Error Details:', error.toJSON());
        }
        
        return {
          success: false,
          error: this.getUserFriendlyMessage(error),
          type: error.type
        };
      } else {
        // Unexpected error
        console.error('Unexpected API error:', error);
        return {
          success: false,
          error: 'An unexpected error occurred. Please try again.',
          type: 'unknown_error'
        };
      }
    }
  }
  
  /**
   * Convert technical errors to user-friendly messages
   */
  private getUserFriendlyMessage(error: HanaQueryClientError): string {
    switch (error.type) {
      case 'network_error':
        return 'Unable to connect to the server. Please check your internet connection and try again.';
      
      case 'timeout_error':
        return 'The request is taking longer than expected. Please try again.';
      
      case 'validation_error':
        return 'Invalid input provided. Please check your data and try again.';
      
      case 'authorization_error':
        return 'You are not authorized to access this resource.';
      
      case 'not_found_error':
        return 'The requested resource was not found.';
      
      case 'server_error':
        return 'A server error occurred. Please try again later.';
      
      default:
        return 'An error occurred while processing your request.';
    }
  }
  
  /**
   * Public methods with consistent error handling
   */
  async getHealthStatus() {
    return this.safeApiCall(() => this.client.getHealth());
  }
  
  async getProductionPlans() {
    return this.safeApiCall(() => this.client.getPlans(), { data: { plans: [] }, metadata: { count: 0 } });
  }
  
  async getPlanDetails(planId: number) {
    return this.safeApiCall(() => this.client.getPlan(planId));
  }
  
  async getInventoryStatus() {
    return this.safeApiCall(() => this.client.getItems());
  }
}

async function productionReadyErrorHandling() {
  console.log('\\n=== Production-Ready Error Handling ===');
  
  const apiService = new RobustAPIService({
    baseUrl: 'http://localhost:3001',
    enableLogging: true,
    logLevel: 'info'
  });
  
  // Test the service methods
  console.log('Testing robust API service...');
  
  const healthResult = await apiService.getHealthStatus();
  if (healthResult.success) {
    console.log('✅ Health check successful:', healthResult.data.data.status);
  } else {
    console.log('❌ Health check failed:', healthResult.error);
  }
  
  const plansResult = await apiService.getProductionPlans();
  if (plansResult.success) {
    console.log(`✅ Found ${plansResult.data.metadata.count} production plans`);
  } else {
    console.log('❌ Failed to get plans:', plansResult.error);
    console.log('Error type:', plansResult.type);
  }
  
  // Test with invalid plan ID
  const invalidPlanResult = await apiService.getPlanDetails(99999);
  if (invalidPlanResult.success) {
    console.log('✅ Plan details retrieved');
  } else {
    console.log('❌ Plan not found:', invalidPlanResult.error);
  }
}

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

async function runErrorHandlingExamples() {
  console.log('🛡️ HANA Query API Client - Error Handling Examples');
  console.log('='.repeat(60));
  
  try {
    await basicErrorHandling();
    await specificErrorHandling();
    await errorTypeGuards();
    await gracefulErrorHandling();
    await customRetryLogic();
    await errorContextAndDebugging();
    await productionReadyErrorHandling();
    
    console.log('\\n✅ All error handling examples completed!');
    
  } catch (error: unknown) {
    console.error('\\n❌ Error handling examples failed:', error);
  }
}

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

export {
  basicErrorHandling,
  specificErrorHandling,
  errorTypeGuards,
  gracefulErrorHandling,
  customRetryLogic,
  errorContextAndDebugging,
  productionReadyErrorHandling,
  RobustAPIService,
  runErrorHandlingExamples
};