<?php

declare(strict_types=1);

/**
 * Test script for the new Memory Management system in Discovery module
 */

require_once __DIR__ . '/../../vendor/autoload.php';

use App\Framework\Cache\Driver\InMemoryCache;
use App\Framework\Cache\GeneralCache;
use App\Framework\Core\PathProvider;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\DateTime\SystemClock;
use App\Framework\DI\DefaultContainer;
use App\Framework\Discovery\Factory\DiscoveryServiceFactory;
use App\Framework\Discovery\Memory\DiscoveryMemoryManager;
use App\Framework\Discovery\ValueObjects\DiscoveryConfiguration;
use App\Framework\Discovery\ValueObjects\DiscoveryOptions;
use App\Framework\Discovery\ValueObjects\MemoryStrategy;
use App\Framework\Discovery\ValueObjects\ScanType;
use App\Framework\Filesystem\FileSystemService;
use App\Framework\Logging\DefaultLogger;
use App\Framework\Logging\Handlers\ConsoleHandler;
use App\Framework\Logging\LogLevel;
use App\Framework\Performance\MemoryMonitor;
use App\Framework\Reflection\CachedReflectionProvider;
use App\Framework\Serializer\Php\PhpSerializer;

echo "🧠 Testing Memory Management System for Discovery Module\n";
echo "=====================================================\n";

try {
    // Setup basic dependencies
    $pathProvider = new PathProvider(__DIR__ . '/../..');
    $cacheDriver = new InMemoryCache();
    $serializer = new PhpSerializer();
    $cache = new GeneralCache($cacheDriver, $serializer);
    $clock = new SystemClock();
    $container = new DefaultContainer();

    // Optional dependencies for testing
    $consoleHandler = new ConsoleHandler();
    $logger = new DefaultLogger(LogLevel::INFO, [$consoleHandler]);
    $memoryMonitor = new MemoryMonitor();
    $reflectionProvider = new CachedReflectionProvider();
    $fileSystemService = new FileSystemService();

    // Register optional services in container
    $container->singleton(\App\Framework\Logging\Logger::class, $logger);
    $container->singleton(\App\Framework\Performance\MemoryMonitor::class, $memoryMonitor);
    $container->singleton(\App\Framework\Reflection\ReflectionProvider::class, $reflectionProvider);
    $container->singleton(\App\Framework\Filesystem\FileSystemService::class, $fileSystemService);

    echo "✅ Dependencies initialized\n";

    // Test 1: Memory Manager Creation and Configuration
    echo "\n🧪 Test 1: Memory Manager Configuration\n";

    $memoryLimit = Byte::fromMegabytes(64);
    $strategy = MemoryStrategy::ADAPTIVE;

    $memoryManager = new DiscoveryMemoryManager(
        strategy: $strategy,
        memoryLimit: $memoryLimit,
        memoryPressureThreshold: 0.7,
        memoryMonitor: $memoryMonitor,
        logger: $logger
    );

    echo "✅ Memory Manager created\n";
    echo "  Strategy: {$strategy->value}\n";
    echo "  Memory Limit: {$memoryLimit->toHumanReadable()}\n";
    echo "  Description: {$memoryManager->getStrategyDescription()}\n";

    // Test 2: Memory Status Monitoring
    echo "\n🧪 Test 2: Memory Status Monitoring\n";

    $memoryStatus = $memoryManager->getMemoryStatus();
    echo "✅ Memory status retrieved\n";
    echo "  Current Status: {$memoryStatus->status->value}\n";
    echo "  Current Usage: {$memoryStatus->currentUsage->toHumanReadable()}\n";
    echo "  Memory Pressure: {$memoryStatus->memoryPressure->toString()}\n";
    echo "  Available Memory: {$memoryStatus->availableMemory->toHumanReadable()}\n";

    // Test 3: Chunk Size Calculation
    echo "\n🧪 Test 3: Adaptive Chunk Size Calculation\n";

    $totalFiles = 1000;
    $optimalChunkSize = $memoryManager->calculateOptimalChunkSize($totalFiles);
    echo "✅ Optimal chunk size calculated\n";
    echo "  Total Files: {$totalFiles}\n";
    echo "  Optimal Chunk Size: {$optimalChunkSize}\n";
    echo "  Estimated Batches: " . ceil($totalFiles / $optimalChunkSize) . "\n";

    // Test 4: Memory Guard Creation and Testing
    echo "\n🧪 Test 4: Memory Guard Operations\n";

    $memoryGuard = $memoryManager->createMemoryGuard();
    echo "✅ Memory Guard created\n";

    // Perform several guard checks
    for ($i = 1; $i <= 5; $i++) {
        $guardResult = $memoryGuard->check();
        echo "  Check {$i}: Status={$guardResult->memoryStatus->status->value}, Actions=" . count($guardResult->actions) . "\n";

        if ($guardResult->requiresImmediateAction()) {
            echo "    ⚠️ Immediate action required!\n";
        }
    }

    $guardStats = $memoryGuard->getStatistics();
    echo "  Guard Statistics: {$guardStats->totalChecks} checks, Emergency Mode: " . ($guardStats->emergencyMode ? 'ON' : 'OFF') . "\n";

    // Test 5: Memory Cleanup
    echo "\n🧪 Test 5: Memory Cleanup Operations\n";

    $beforeCleanup = Byte::fromBytes(memory_get_usage(true));
    echo "  Memory before cleanup: {$beforeCleanup->toHumanReadable()}\n";

    $cleanupResult = $memoryManager->performCleanup();
    echo "✅ Memory cleanup performed\n";
    echo "  Memory freed: {$cleanupResult->memoryFreed->toHumanReadable()}\n";
    echo "  Collected cycles: {$cleanupResult->collectedCycles}\n";
    echo "  Was effective: " . ($cleanupResult->wasEffective() ? 'Yes' : 'No') . "\n";

    // Test 6: Memory Strategy Suggestions
    echo "\n🧪 Test 6: Memory Strategy Suggestions\n";

    $testCases = [
        ['files' => 100, 'memory' => 32, 'desc' => 'Small project, low memory'],
        ['files' => 5000, 'memory' => 128, 'desc' => 'Medium project, normal memory'],
        ['files' => 50000, 'memory' => 256, 'desc' => 'Large project, high memory'],
        ['files' => 1000, 'memory' => 64, 'desc' => 'Normal project, limited memory'],
    ];

    foreach ($testCases as $case) {
        $suggestedStrategy = MemoryStrategy::suggestForDiscovery(
            $case['files'],
            $case['memory'],
            true
        );
        echo "  {$case['desc']}: {$suggestedStrategy->value}\n";
    }

    // Test 7: Batch Parameter Calculation
    echo "\n🧪 Test 7: Batch Parameter Calculation\n";

    $averageFileSize = Byte::fromKilobytes(25); // 25KB average file
    $batchParams = $memoryManager->calculateBatchParameters(500, $averageFileSize);

    echo "✅ Batch parameters calculated\n";
    echo "  Chunk Size: {$batchParams->chunkSize}\n";
    echo "  Batch Count: {$batchParams->batchCount}\n";
    echo "  Memory per Batch: {$batchParams->estimatedMemoryPerBatch->toHumanReadable()}\n";
    echo "  Strategy: {$batchParams->strategy->value}\n";

    // Test 8: Service Integration Test
    echo "\n🧪 Test 8: Service Integration Test\n";

    // Create factory
    $factory = new DiscoveryServiceFactory($container, $pathProvider, $cache, $clock);

    // Create configuration with memory management enabled
    $config = new DiscoveryConfiguration(
        paths: [$pathProvider->getBasePath() . '/src/Application/Admin'],
        useCache: false,
        enableMemoryMonitoring: true,
        enablePerformanceTracking: true,
        memoryLimitMB: 32, // Low limit to test chunking
        maxFilesPerBatch: 10 // Small batches
    );

    // Create service with memory management
    $discoveryService = $factory->create($config);
    echo "✅ Discovery service created with memory management\n";

    // Get health status to verify memory management integration
    $healthStatus = $discoveryService->getHealthStatus();
    if (isset($healthStatus['memory_management'])) {
        echo "✅ Memory management integrated successfully\n";
        echo "  Strategy: {$healthStatus['memory_management']['strategy']}\n";
        echo "  Memory Limit: {$healthStatus['memory_management']['memory_limit']}\n";
        echo "  Current Usage: {$healthStatus['memory_management']['current_usage']}\n";
    }

    // Get memory statistics
    $memoryStats = $discoveryService->getMemoryStatistics();
    echo "✅ Memory statistics available\n";
    echo "  Strategy Description: {$memoryStats['strategy_description']}\n";
    echo "  Recommendations: " . count($memoryStats['recommendations']) . " items\n";

    // Test 9: Quick Discovery Run with Memory Management
    echo "\n🧪 Test 9: Quick Discovery Run with Memory Management\n";

    $startTime = microtime(true);
    $startMemory = Byte::fromBytes(memory_get_usage(true));

    $options = new DiscoveryOptions(
        scanType: ScanType::FULL,
        paths: [$pathProvider->getBasePath() . '/src/Application/Admin'],
        useCache: false
    );

    $registry = $discoveryService->discoverWithOptions($options);

    $endTime = microtime(true);
    $endMemory = Byte::fromBytes(memory_get_usage(true));

    echo "✅ Discovery with memory management completed\n";
    echo "  Processing Time: " . round(($endTime - $startTime) * 1000, 2) . "ms\n";
    echo "  Memory Used: " . $endMemory->subtract($startMemory)->toHumanReadable() . "\n";
    echo "  Peak Memory: " . Byte::fromBytes(memory_get_peak_usage(true))->toHumanReadable() . "\n";
    echo "  Registry Size: " . count($registry) . " items\n";

    // Final memory statistics
    $finalMemoryStats = $discoveryService->getMemoryStatistics();
    echo "  Final Memory Status: {$finalMemoryStats['memory_status']['status']}\n";
    echo "  Guard Checks: {$finalMemoryStats['guard_statistics']['total_checks']}\n";

    if (! empty($finalMemoryStats['chunking_performance'])) {
        echo "  Chunks Processed: {$finalMemoryStats['chunking_performance']['total_chunks_processed']}\n";
        echo "  Average Chunk Size: " . round($finalMemoryStats['chunking_performance']['average_chunk_size'], 1) . "\n";
    }

    echo "\n🎉 All memory management tests passed successfully!\n";
    echo "\n🏆 Key Memory Management Features Verified:\n";
    echo "  ✅ Adaptive memory strategy selection\n";
    echo "  ✅ Real-time memory monitoring and guards\n";
    echo "  ✅ Intelligent chunk size calculation\n";
    echo "  ✅ Memory cleanup and leak detection\n";
    echo "  ✅ Batch parameter optimization\n";
    echo "  ✅ Emergency memory handling\n";
    echo "  ✅ Full Discovery service integration\n";
    echo "  ✅ Performance tracking and statistics\n";

} catch (Throwable $e) {
    echo "\n❌ Error during memory management testing:\n";
    echo "  Message: " . $e->getMessage() . "\n";
    echo "  File: " . $e->getFile() . ":" . $e->getLine() . "\n";
    echo "  Stack trace:\n" . $e->getTraceAsString() . "\n";
    exit(1);
}
