#!/usr/bin/env ts-node

import { config } from '../config/env';
import { fileStorageService } from '../services/fileStorageService';

interface TestResult {
  test: string;
  status: 'PASS' | 'FAIL';
  message: string;
  duration: number;
}

class StagingEnvironmentTester {
  private results: TestResult[] = [];

  async runAllTests(): Promise<void> {
    console.log('🚀 Starting Staging Environment Tests...\n');

    await this.testEnvironmentConfiguration();
    await this.testGCSConnection();
    await this.testDatabaseConnection();
    await this.testAuthenticationConfiguration();
    await this.testUploadPipeline();
    await this.testErrorHandling();

    this.printResults();
  }

  private async testEnvironmentConfiguration(): Promise<void> {
    const startTime = Date.now();
    
    try {
      // Test required environment variables
      const requiredConfigs = [
        'googleCloud.gcsBucketName',
        'googleCloud.projectId',
        'googleCloud.applicationCredentials',
        'supabase.url',
        'jwt.secret',
      ];

      for (const configPath of requiredConfigs) {
        const value = this.getNestedValue(config, configPath);
        if (!value) {
          throw new Error(`Missing required configuration: ${configPath}`);
        }
      }

      // Verify no local storage configuration - uploadDir should be temporary only
      if (config.upload?.uploadDir && !config.upload.uploadDir.includes('/tmp/')) {
        throw new Error('Local storage configuration should not be present in cloud-only architecture');
      }

      this.addResult('Environment Configuration', 'PASS', 'All required configurations present', Date.now() - startTime);
    } catch (error) {
      this.addResult('Environment Configuration', 'FAIL', (error as Error).message, Date.now() - startTime);
    }
  }

  private async testGCSConnection(): Promise<void> {
    const startTime = Date.now();
    
    try {
      const isConnected = await fileStorageService.testConnection();
      
      if (!isConnected) {
        throw new Error('Failed to connect to Google Cloud Storage');
      }

      // Test basic GCS operations
      const stats = await fileStorageService.getStorageStats('uploads/');
      console.log(`📊 GCS Storage Stats: ${stats.totalFiles} files, ${stats.totalSize} bytes`);

      this.addResult('GCS Connection', 'PASS', 'Successfully connected to GCS', Date.now() - startTime);
    } catch (error) {
      this.addResult('GCS Connection', 'FAIL', (error as Error).message, Date.now() - startTime);
    }
  }

  private async testDatabaseConnection(): Promise<void> {
    const startTime = Date.now();
    
    try {
      // Test database connection by checking Supabase configuration
      const isConnected = config.supabase.url && config.supabase.anonKey;
      
      if (!isConnected) {
        throw new Error('Failed to connect to database');
      }

      this.addResult('Database Connection', 'PASS', 'Successfully connected to database', Date.now() - startTime);
    } catch (error) {
      this.addResult('Database Connection', 'FAIL', (error as Error).message, Date.now() - startTime);
    }
  }

  private async testAuthenticationConfiguration(): Promise<void> {
    const startTime = Date.now();
    
    try {
      // Test Firebase Admin initialization
      const admin = require('firebase-admin');
      
      // Import the Firebase config to ensure it's initialized
      require('../config/firebase');
      
      if (!admin.apps.length) {
        throw new Error('Firebase Admin not initialized');
      }

      this.addResult('Authentication Configuration', 'PASS', 'Firebase Admin properly configured', Date.now() - startTime);
    } catch (error) {
      this.addResult('Authentication Configuration', 'FAIL', (error as Error).message, Date.now() - startTime);
    }
  }

  private async testUploadPipeline(): Promise<void> {
    const startTime = Date.now();
    
    try {
      // Test file upload simulation
      const testFile = {
        originalname: 'test-staging.pdf',
        filename: 'test-staging-file.pdf',
        path: '/tmp/test-staging-file.pdf',
        size: 1024,
        mimetype: 'application/pdf',
        buffer: Buffer.from('test staging content'),
      };

      const result = await fileStorageService.storeFile(testFile, 'staging-test-user');
      
      if (!result.success) {
        throw new Error(`Upload failed: ${result.error}`);
      }

      // Clean up test file
      if (result.fileInfo?.gcsPath) {
        await fileStorageService.deleteFile(result.fileInfo.gcsPath);
      }

      this.addResult('Upload Pipeline', 'PASS', 'File upload and deletion successful', Date.now() - startTime);
    } catch (error) {
      this.addResult('Upload Pipeline', 'FAIL', (error as Error).message, Date.now() - startTime);
    }
  }

  private async testErrorHandling(): Promise<void> {
    const startTime = Date.now();
    
    try {
      // Test error handling with invalid file
      const invalidFile = {
        originalname: 'invalid.exe',
        filename: 'invalid-file.exe',
        path: '/tmp/invalid-file.exe',
        size: 1024,
        mimetype: 'application/exe',
        buffer: Buffer.from('invalid content'),
      };

      const result = await fileStorageService.storeFile(invalidFile, 'staging-test-user');
      
      // The file storage service should accept the file (it's just storage)
      // The validation happens at the upload middleware level, not storage level
      if (!result.success) {
        throw new Error('File storage should accept any file type - validation happens at upload level');
      }

      this.addResult('Error Handling', 'PASS', 'File storage accepts files, validation happens at upload level', Date.now() - startTime);
    } catch (error) {
      this.addResult('Error Handling', 'FAIL', (error as Error).message, Date.now() - startTime);
    }
  }

  private getNestedValue(obj: any, path: string): any {
    return path.split('.').reduce((current, key) => current?.[key], obj);
  }

  private addResult(test: string, status: 'PASS' | 'FAIL', message: string, duration: number): void {
    this.results.push({ test, status, message, duration });
  }

  private printResults(): void {
    console.log('\n📋 Test Results Summary:');
    console.log('=' .repeat(60));
    
    let passed = 0;
    let failed = 0;
    let totalDuration = 0;

    this.results.forEach(result => {
      const statusIcon = result.status === 'PASS' ? '✅' : '❌';
      console.log(`${statusIcon} ${result.test}: ${result.status}`);
      console.log(`   ${result.message}`);
      console.log(`   Duration: ${result.duration}ms\n`);
      
      if (result.status === 'PASS') passed++;
      else failed++;
      totalDuration += result.duration;
    });

    console.log('=' .repeat(60));
    console.log(`Total Tests: ${this.results.length}`);
    console.log(`Passed: ${passed} | Failed: ${failed}`);
    console.log(`Total Duration: ${totalDuration}ms`);
    
    if (failed > 0) {
      console.log('\n❌ Some tests failed. Please check the configuration.');
      process.exit(1);
    } else {
      console.log('\n✅ All tests passed! Staging environment is ready.');
    }
  }
}

// Run tests if this script is executed directly
if (require.main === module) {
  const tester = new StagingEnvironmentTester();
  tester.runAllTests().catch(error => {
    console.error('Test execution failed:', error);
    process.exit(1);
  });
}

export { StagingEnvironmentTester }; 