<?php

declare(strict_types=1);

use App\Framework\Queue\ValueObjects\JobId;
use App\Framework\Queue\ValueObjects\JobMetrics;

describe('JobMetrics Value Object', function () {

    describe('Creation and Basic Properties', function () {
        it('can create job metrics with minimal parameters', function () {
            $jobId = JobId::generate()->toString();
            $queueName = 'email-queue';

            $metrics = JobMetrics::create($jobId, $queueName);

            expect($metrics->jobId)->toBe($jobId);
            expect($metrics->queueName)->toBe($queueName);
            expect($metrics->status)->toBe('pending');
            expect($metrics->attempts)->toBe(0);
            expect($metrics->maxAttempts)->toBe(3);
            expect($metrics->executionTimeMs)->toBe(0.0);
            expect($metrics->memoryUsageBytes)->toBe(0);
            expect($metrics->errorMessage)->toBeNull();
            expect($metrics->createdAt)->toBeString();
            expect($metrics->startedAt)->toBeNull();
            expect($metrics->completedAt)->toBeNull();
            expect($metrics->failedAt)->toBeNull();
            expect($metrics->metadata)->toBe([]);
        });

        it('can create job metrics with custom parameters', function () {
            $jobId = JobId::generate()->toString();
            $queueName = 'report-queue';
            $status = 'running';
            $attempts = 2;
            $maxAttempts = 5;

            $metrics = JobMetrics::create($jobId, $queueName, $status, $attempts, $maxAttempts);

            expect($metrics->status)->toBe($status);
            expect($metrics->attempts)->toBe($attempts);
            expect($metrics->maxAttempts)->toBe($maxAttempts);
        });

        it('is readonly and immutable', function () {
            $metrics = JobMetrics::create('test-job', 'test-queue');

            $reflection = new ReflectionClass($metrics);
            expect($reflection->isReadOnly())->toBeTrue();

            // All properties should be readonly
            $properties = ['jobId', 'queueName', 'status', 'attempts', 'maxAttempts',
                          'executionTimeMs', 'memoryUsageBytes', 'errorMessage',
                          'createdAt', 'startedAt', 'completedAt', 'failedAt', 'metadata'];

            foreach ($properties as $prop) {
                $property = $reflection->getProperty($prop);
                expect($property->isReadOnly())->toBeTrue("Property {$prop} should be readonly");
            }
        });
    });

    describe('Job State Transitions', function () {
        beforeEach(function () {
            $this->baseMetrics = JobMetrics::create('test-job-123', 'email-queue');
        });

        it('can transition from pending to running', function () {
            $startTime = microtime(true) * 1000; // milliseconds
            $memoryUsage = 1024 * 1024; // 1MB

            $runningMetrics = $this->baseMetrics->withStarted($startTime, $memoryUsage);

            expect($runningMetrics->status)->toBe('running');
            expect($runningMetrics->attempts)->toBe(1); // Incremented from 0
            expect($runningMetrics->executionTimeMs)->toBe($startTime);
            expect($runningMetrics->memoryUsageBytes)->toBe($memoryUsage);
            expect($runningMetrics->startedAt)->toBeString();
            expect($runningMetrics->startedAt)->not->toBeNull();

            // Original should be unchanged
            expect($this->baseMetrics->status)->toBe('pending');
            expect($this->baseMetrics->attempts)->toBe(0);
        });

        it('can transition from running to completed', function () {
            $startTime = microtime(true) * 1000;
            $runningMetrics = $this->baseMetrics->withStarted($startTime, 1024 * 1024);

            $totalExecutionTime = 5500.0; // 5.5 seconds in milliseconds
            $peakMemoryUsage = 2 * 1024 * 1024; // 2MB

            $completedMetrics = $runningMetrics->withCompleted($totalExecutionTime, $peakMemoryUsage);

            expect($completedMetrics->status)->toBe('completed');
            expect($completedMetrics->executionTimeMs)->toBe($totalExecutionTime);
            expect($completedMetrics->memoryUsageBytes)->toBe($peakMemoryUsage);
            expect($completedMetrics->completedAt)->toBeString();
            expect($completedMetrics->completedAt)->not->toBeNull();
            expect($completedMetrics->attempts)->toBe(1); // Same as running state
        });

        it('can transition from running to failed', function () {
            $startTime = microtime(true) * 1000;
            $runningMetrics = $this->baseMetrics->withStarted($startTime, 1024 * 1024);

            $errorMessage = 'Database connection timeout';
            $executionTime = 2500.0; // 2.5 seconds
            $memoryUsage = 1.5 * 1024 * 1024; // 1.5MB

            $failedMetrics = $runningMetrics->withFailed($errorMessage, $executionTime, $memoryUsage);

            expect($failedMetrics->status)->toBe('failed');
            expect($failedMetrics->errorMessage)->toBe($errorMessage);
            expect($failedMetrics->executionTimeMs)->toBe($executionTime);
            expect($failedMetrics->memoryUsageBytes)->toBe($memoryUsage);
            expect($failedMetrics->failedAt)->toBeString();
            expect($failedMetrics->failedAt)->not->toBeNull();
        });

        it('preserves metadata across state transitions', function () {
            $originalMetadata = ['batch_id' => 123, 'priority' => 'high'];
            $metricsWithMetadata = $this->baseMetrics->withMetadata($originalMetadata);

            $runningMetrics = $metricsWithMetadata->withStarted(1000.0, 1024 * 1024);
            expect($runningMetrics->metadata)->toBe($originalMetadata);

            $completedMetrics = $runningMetrics->withCompleted(5000.0, 2 * 1024 * 1024);
            expect($completedMetrics->metadata)->toBe($originalMetadata);
        });
    });

    describe('Metadata Management', function () {
        beforeEach(function () {
            $this->baseMetrics = JobMetrics::create('test-job', 'test-queue');
        });

        it('can add metadata to metrics', function () {
            $metadata = [
                'user_id' => 12345,
                'email_template' => 'newsletter',
                'batch_size' => 1000,
            ];

            $metricsWithMetadata = $this->baseMetrics->withMetadata($metadata);

            expect($metricsWithMetadata->metadata)->toBe($metadata);
            expect($this->baseMetrics->metadata)->toBe([]); // Original unchanged
        });

        it('merges metadata when called multiple times', function () {
            $firstMetadata = ['user_id' => 123, 'type' => 'email'];
            $secondMetadata = ['priority' => 'high', 'retry_count' => 2];

            $metrics = $this->baseMetrics
                ->withMetadata($firstMetadata)
                ->withMetadata($secondMetadata);

            expect($metrics->metadata)->toBe([
                'user_id' => 123,
                'type' => 'email',
                'priority' => 'high',
                'retry_count' => 2,
            ]);
        });

        it('overwrites existing metadata keys', function () {
            $firstMetadata = ['priority' => 'low', 'attempts' => 1];
            $secondMetadata = ['priority' => 'high']; // Overwrites priority

            $metrics = $this->baseMetrics
                ->withMetadata($firstMetadata)
                ->withMetadata($secondMetadata);

            expect($metrics->metadata['priority'])->toBe('high');
            expect($metrics->metadata['attempts'])->toBe(1); // Preserved
        });
    });

    describe('Status Check Methods', function () {
        beforeEach(function () {
            $this->jobId = 'status-test-job';
            $this->queueName = 'status-queue';
        });

        it('correctly identifies pending status', function () {
            $metrics = JobMetrics::create($this->jobId, $this->queueName, 'pending');

            expect($metrics->isPending())->toBeTrue();
            expect($metrics->isRunning())->toBeFalse();
            expect($metrics->isCompleted())->toBeFalse();
            expect($metrics->isFailed())->toBeFalse();
        });

        it('correctly identifies running status', function () {
            $metrics = JobMetrics::create($this->jobId, $this->queueName, 'running');

            expect($metrics->isRunning())->toBeTrue();
            expect($metrics->isPending())->toBeFalse();
            expect($metrics->isCompleted())->toBeFalse();
            expect($metrics->isFailed())->toBeFalse();
        });

        it('correctly identifies completed status', function () {
            $metrics = JobMetrics::create($this->jobId, $this->queueName, 'completed');

            expect($metrics->isCompleted())->toBeTrue();
            expect($metrics->isPending())->toBeFalse();
            expect($metrics->isRunning())->toBeFalse();
            expect($metrics->isFailed())->toBeFalse();
        });

        it('correctly identifies failed status', function () {
            $metrics = JobMetrics::create($this->jobId, $this->queueName, 'failed');

            expect($metrics->isFailed())->toBeTrue();
            expect($metrics->isPending())->toBeFalse();
            expect($metrics->isRunning())->toBeFalse();
            expect($metrics->isCompleted())->toBeFalse();
        });

        it('correctly checks max attempts', function () {
            $metrics = JobMetrics::create($this->jobId, $this->queueName, 'running', 2, 3);
            expect($metrics->hasMaxAttempts())->toBeFalse();

            $maxedMetrics = JobMetrics::create($this->jobId, $this->queueName, 'failed', 3, 3);
            expect($maxedMetrics->hasMaxAttempts())->toBeTrue();

            $exceededMetrics = JobMetrics::create($this->jobId, $this->queueName, 'failed', 5, 3);
            expect($exceededMetrics->hasMaxAttempts())->toBeTrue();
        });
    });

    describe('Calculation Methods', function () {
        it('calculates success rate correctly', function () {
            // Job not started yet
            $pendingMetrics = JobMetrics::create('job', 'queue', 'pending', 0);
            expect($pendingMetrics->getSuccessRate()->getValue())->toBe(100.0);

            // Failed job with attempts
            $failedMetrics = JobMetrics::create('job', 'queue', 'failed', 2);
            expect($failedMetrics->getSuccessRate()->getValue())->toBe(0.0);

            // Completed job
            $completedMetrics = JobMetrics::create('job', 'queue', 'completed', 1);
            expect($completedMetrics->getSuccessRate()->getValue())->toBe(100.0);
        });

        it('converts execution time from milliseconds to seconds', function () {
            $metrics = JobMetrics::create('job', 'queue')
                ->withCompleted(5500.0, 1024 * 1024); // 5.5 seconds

            expect($metrics->getExecutionTimeSeconds())->toBe(5.5);
        });

        it('converts memory usage from bytes to MB', function () {
            $metrics = JobMetrics::create('job', 'queue')
                ->withCompleted(1000.0, 2.5 * 1024 * 1024); // 2.5 MB

            expect($metrics->getMemoryUsageMB())->toBe(2.5);
        });

        it('calculates duration correctly', function () {
            $metrics = JobMetrics::create('job', 'queue');

            // No duration for pending job
            expect($metrics->getDuration())->toBeNull();

            // Mock started/completed times
            $startedMetrics = new JobMetrics(
                jobId: 'job',
                queueName: 'queue',
                status: 'completed',
                attempts: 1,
                maxAttempts: 3,
                executionTimeMs: 1000.0,
                memoryUsageBytes: 1024,
                errorMessage: null,
                createdAt: '2024-01-01 10:00:00',
                startedAt: '2024-01-01 10:00:05',
                completedAt: '2024-01-01 10:00:15',
                failedAt: null
            );

            $duration = $startedMetrics->getDuration();
            expect($duration)->toBe(10); // 10 seconds difference
        });

        it('calculates duration for failed jobs', function () {
            $failedMetrics = new JobMetrics(
                jobId: 'job',
                queueName: 'queue',
                status: 'failed',
                attempts: 2,
                maxAttempts: 3,
                executionTimeMs: 500.0,
                memoryUsageBytes: 1024,
                errorMessage: 'Error occurred',
                createdAt: '2024-01-01 10:00:00',
                startedAt: '2024-01-01 10:00:05',
                completedAt: null,
                failedAt: '2024-01-01 10:00:08'
            );

            $duration = $failedMetrics->getDuration();
            expect($duration)->toBe(3); // 3 seconds from start to failure
        });
    });

    describe('Array Conversion', function () {
        it('provides comprehensive metrics information', function () {
            $metrics = JobMetrics::create('test-job-456', 'email-queue', 'completed', 1, 3)
                ->withCompleted(3750.0, 1.5 * 1024 * 1024)
                ->withMetadata(['batch_id' => 789, 'template' => 'welcome']);

            $array = $metrics->toArray();

            // Verify all expected keys exist
            $expectedKeys = [
                'job_id', 'queue_name', 'status', 'attempts', 'max_attempts',
                'execution_time_ms', 'execution_time_seconds', 'memory_usage_bytes',
                'memory_usage_mb', 'success_rate', 'duration_seconds', 'error_message',
                'created_at', 'started_at', 'completed_at', 'failed_at', 'metadata',
            ];

            foreach ($expectedKeys as $key) {
                expect($array)->toHaveKey($key);
            }

            // Verify calculated values
            expect($array['job_id'])->toBe('test-job-456');
            expect($array['queue_name'])->toBe('email-queue');
            expect($array['status'])->toBe('completed');
            expect($array['execution_time_seconds'])->toBe(3.75);
            expect($array['memory_usage_mb'])->toBe(1.5);
            expect($array['success_rate'])->toBe(100.0);
            expect($array['metadata'])->toBe(['batch_id' => 789, 'template' => 'welcome']);
        });

        it('handles null values correctly in array conversion', function () {
            $pendingMetrics = JobMetrics::create('pending-job', 'test-queue');
            $array = $pendingMetrics->toArray();

            expect($array['error_message'])->toBeNull();
            expect($array['started_at'])->toBeNull();
            expect($array['completed_at'])->toBeNull();
            expect($array['failed_at'])->toBeNull();
            expect($array['duration_seconds'])->toBeNull();
        });
    });

    describe('Edge Cases and Error Handling', function () {
        it('handles zero execution time', function () {
            $metrics = JobMetrics::create('instant-job', 'fast-queue')
                ->withCompleted(0.0, 1024);

            expect($metrics->getExecutionTimeSeconds())->toBe(0.0);
        });

        it('handles zero memory usage', function () {
            $metrics = JobMetrics::create('no-memory-job', 'efficient-queue')
                ->withCompleted(1000.0, 0);

            expect($metrics->getMemoryUsageMB())->toBe(0.0);
        });

        it('handles very large execution times', function () {
            $largeTime = 3600000.0; // 1 hour in milliseconds
            $metrics = JobMetrics::create('long-job', 'slow-queue')
                ->withCompleted($largeTime, 1024);

            expect($metrics->getExecutionTimeSeconds())->toBe(3600.0); // 1 hour
        });

        it('handles very large memory usage', function () {
            $largeMemory = 10 * 1024 * 1024 * 1024; // 10GB
            $metrics = JobMetrics::create('memory-intensive-job', 'heavy-queue')
                ->withCompleted(1000.0, $largeMemory);

            expect($metrics->getMemoryUsageMB())->toBe(10240.0); // 10GB in MB
        });

        it('handles empty metadata gracefully', function () {
            $metrics = JobMetrics::create('no-metadata-job', 'simple-queue')
                ->withMetadata([]);

            expect($metrics->metadata)->toBe([]);
        });

        it('handles complex metadata structures', function () {
            $complexMetadata = [
                'nested' => ['level1' => ['level2' => 'value']],
                'array' => [1, 2, 3, 4, 5],
                'mixed' => ['string', 42, true, null],
            ];

            $metrics = JobMetrics::create('complex-job', 'data-queue')
                ->withMetadata($complexMetadata);

            expect($metrics->metadata)->toBe($complexMetadata);
        });
    });
});

describe('Job Metrics Collection Mock System', function () {

    beforeEach(function () {
        // Create a mock metrics manager for testing
        $this->metricsManager = new class () {
            private array $jobMetrics = [];

            private array $queueStats = [];

            public function recordJobExecution(string $jobId, float $executionTimeMs, int $memoryUsage): void
            {
                if (! isset($this->jobMetrics[$jobId])) {
                    $this->jobMetrics[$jobId] = JobMetrics::create($jobId, 'default-queue');
                }

                $this->jobMetrics[$jobId] = $this->jobMetrics[$jobId]
                    ->withCompleted($executionTimeMs, $memoryUsage);
            }

            public function recordJobFailure(string $jobId, string $errorMessage, float $executionTimeMs, int $memoryUsage): void
            {
                if (! isset($this->jobMetrics[$jobId])) {
                    $this->jobMetrics[$jobId] = JobMetrics::create($jobId, 'default-queue');
                }

                $this->jobMetrics[$jobId] = $this->jobMetrics[$jobId]
                    ->withFailed($errorMessage, $executionTimeMs, $memoryUsage);
            }

            public function getJobMetrics(string $jobId): ?JobMetrics
            {
                return $this->jobMetrics[$jobId] ?? null;
            }

            public function getQueueMetrics(string $queueName): array
            {
                $jobs = array_filter($this->jobMetrics, fn ($metrics) => $metrics->queueName === $queueName);

                if (empty($jobs)) {
                    return [
                        'queue_name' => $queueName,
                        'total_jobs' => 0,
                        'completed_jobs' => 0,
                        'failed_jobs' => 0,
                        'average_execution_time_ms' => 0.0,
                        'average_memory_usage_mb' => 0.0,
                        'success_rate' => 100.0,
                    ];
                }

                $totalJobs = count($jobs);
                $completedJobs = count(array_filter($jobs, fn ($m) => $m->isCompleted()));
                $failedJobs = count(array_filter($jobs, fn ($m) => $m->isFailed()));
                $avgExecutionTime = array_sum(array_map(fn ($m) => $m->executionTimeMs, $jobs)) / $totalJobs;
                $avgMemoryUsage = array_sum(array_map(fn ($m) => $m->getMemoryUsageMB(), $jobs)) / $totalJobs;
                $successRate = ($completedJobs / $totalJobs) * 100;

                return [
                    'queue_name' => $queueName,
                    'total_jobs' => $totalJobs,
                    'completed_jobs' => $completedJobs,
                    'failed_jobs' => $failedJobs,
                    'average_execution_time_ms' => round($avgExecutionTime, 2),
                    'average_memory_usage_mb' => round($avgMemoryUsage, 2),
                    'success_rate' => round($successRate, 2),
                ];
            }

            public function getSystemMetrics(): array
            {
                if (empty($this->jobMetrics)) {
                    return [
                        'total_jobs' => 0,
                        'completed_jobs' => 0,
                        'failed_jobs' => 0,
                        'running_jobs' => 0,
                        'overall_success_rate' => 100.0,
                        'average_execution_time_ms' => 0.0,
                        'peak_memory_usage_mb' => 0.0,
                    ];
                }

                $totalJobs = count($this->jobMetrics);
                $completedJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isCompleted()));
                $failedJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isFailed()));
                $runningJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isRunning()));
                $overallSuccessRate = ($completedJobs / $totalJobs) * 100;
                $avgExecutionTime = array_sum(array_map(fn ($m) => $m->executionTimeMs, $this->jobMetrics)) / $totalJobs;
                $peakMemoryUsage = max(array_map(fn ($m) => $m->getMemoryUsageMB(), $this->jobMetrics));

                return [
                    'total_jobs' => $totalJobs,
                    'completed_jobs' => $completedJobs,
                    'failed_jobs' => $failedJobs,
                    'running_jobs' => $runningJobs,
                    'overall_success_rate' => round($overallSuccessRate, 2),
                    'average_execution_time_ms' => round($avgExecutionTime, 2),
                    'peak_memory_usage_mb' => round($peakMemoryUsage, 2),
                ];
            }

            public function getTopSlowJobs(int $limit = 10): array
            {
                $jobs = $this->jobMetrics;
                usort($jobs, fn ($a, $b) => $b->executionTimeMs <=> $a->executionTimeMs);

                return array_slice($jobs, 0, $limit);
            }

            public function getTopMemoryJobs(int $limit = 10): array
            {
                $jobs = $this->jobMetrics;
                usort($jobs, fn ($a, $b) => $b->memoryUsageBytes <=> $a->memoryUsageBytes);

                return array_slice($jobs, 0, $limit);
            }

            public function getJobsByQueue(string $queueName): array
            {
                return array_filter($this->jobMetrics, fn ($metrics) => $metrics->queueName === $queueName);
            }
        };
    });

    describe('Job Metrics Recording', function () {
        it('can record successful job execution', function () {
            $jobId = 'success-job-123';
            $executionTime = 2500.0; // 2.5 seconds
            $memoryUsage = 3 * 1024 * 1024; // 3MB

            $this->metricsManager->recordJobExecution($jobId, $executionTime, $memoryUsage);

            $metrics = $this->metricsManager->getJobMetrics($jobId);
            expect($metrics)->not->toBeNull();
            expect($metrics->isCompleted())->toBeTrue();
            expect($metrics->executionTimeMs)->toBe($executionTime);
            expect($metrics->memoryUsageBytes)->toBe($memoryUsage);
        });

        it('can record failed job execution', function () {
            $jobId = 'failed-job-456';
            $errorMessage = 'Database connection timeout';
            $executionTime = 1200.0; // 1.2 seconds
            $memoryUsage = 1.5 * 1024 * 1024; // 1.5MB

            $this->metricsManager->recordJobFailure($jobId, $errorMessage, $executionTime, $memoryUsage);

            $metrics = $this->metricsManager->getJobMetrics($jobId);
            expect($metrics)->not->toBeNull();
            expect($metrics->isFailed())->toBeTrue();
            expect($metrics->errorMessage)->toBe($errorMessage);
            expect($metrics->executionTimeMs)->toBe($executionTime);
            expect($metrics->memoryUsageBytes)->toBe($memoryUsage);
        });

        it('handles non-existent job metrics', function () {
            $metrics = $this->metricsManager->getJobMetrics('non-existent-job');
            expect($metrics)->toBeNull();
        });
    });

    describe('Queue-Level Metrics', function () {
        beforeEach(function () {
            // Set up test data with different queue metrics
            // Email queue jobs
            $this->metricsManager->recordJobExecution('email-1', 1500.0, 2 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('email-2', 2000.0, 2.5 * 1024 * 1024);
            $this->metricsManager->recordJobFailure('email-3', 'SMTP error', 800.0, 1 * 1024 * 1024);

            // Report queue jobs
            $this->metricsManager->recordJobExecution('report-1', 5000.0, 10 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('report-2', 7500.0, 15 * 1024 * 1024);
        });

        it('calculates queue metrics correctly', function () {
            $emailMetrics = $this->metricsManager->getQueueMetrics('email-queue');

            expect($emailMetrics['queue_name'])->toBe('email-queue');
            expect($emailMetrics['total_jobs'])->toBe(3);
            expect($emailMetrics['completed_jobs'])->toBe(2);
            expect($emailMetrics['failed_jobs'])->toBe(1);
            expect($emailMetrics['success_rate'])->toBe(66.67); // 2/3 * 100
        });

        it('handles empty queue metrics', function () {
            $emptyMetrics = $this->metricsManager->getQueueMetrics('empty-queue');

            expect($emptyMetrics['total_jobs'])->toBe(0);
            expect($emptyMetrics['completed_jobs'])->toBe(0);
            expect($emptyMetrics['failed_jobs'])->toBe(0);
            expect($emptyMetrics['success_rate'])->toBe(100.0);
            expect($emptyMetrics['average_execution_time_ms'])->toBe(0.0);
        });
    });

    describe('System-Level Metrics', function () {
        beforeEach(function () {
            // Add various jobs across different queues
            $this->metricsManager->recordJobExecution('job-1', 1000.0, 1 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('job-2', 2000.0, 2 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('job-3', 3000.0, 4 * 1024 * 1024);
            $this->metricsManager->recordJobFailure('job-4', 'Error', 500.0, 0.5 * 1024 * 1024);
            $this->metricsManager->recordJobFailure('job-5', 'Error', 750.0, 1 * 1024 * 1024);
        });

        it('calculates system-wide metrics correctly', function () {
            $systemMetrics = $this->metricsManager->getSystemMetrics();

            expect($systemMetrics['total_jobs'])->toBe(5);
            expect($systemMetrics['completed_jobs'])->toBe(3);
            expect($systemMetrics['failed_jobs'])->toBe(2);
            expect($systemMetrics['overall_success_rate'])->toBe(60.0); // 3/5 * 100
            expect($systemMetrics['average_execution_time_ms'])->toBe(1450.0); // (1000+2000+3000+500+750)/5
            expect($systemMetrics['peak_memory_usage_mb'])->toBe(4.0); // Highest from job-3
        });

        it('handles empty system gracefully', function () {
            $emptyManager = new class () {
                private array $jobMetrics = [];

                public function getSystemMetrics(): array
                {
                    return [
                        'total_jobs' => 0,
                        'completed_jobs' => 0,
                        'failed_jobs' => 0,
                        'running_jobs' => 0,
                        'overall_success_rate' => 100.0,
                        'average_execution_time_ms' => 0.0,
                        'peak_memory_usage_mb' => 0.0,
                    ];
                }
            };

            $systemMetrics = $emptyManager->getSystemMetrics();
            expect($systemMetrics['total_jobs'])->toBe(0);
            expect($systemMetrics['overall_success_rate'])->toBe(100.0);
        });
    });

    describe('Performance Analysis', function () {
        beforeEach(function () {
            // Add jobs with varying performance characteristics
            $this->metricsManager->recordJobExecution('fast-job', 100.0, 0.5 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('medium-job', 2500.0, 2 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('slow-job', 10000.0, 1 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('memory-heavy', 1500.0, 50 * 1024 * 1024);
            $this->metricsManager->recordJobExecution('balanced-job', 3000.0, 3 * 1024 * 1024);
        });

        it('identifies slowest jobs correctly', function () {
            $slowJobs = $this->metricsManager->getTopSlowJobs(3);

            expect(count($slowJobs))->toBe(3);
            expect($slowJobs[0]->jobId)->toBe('slow-job');
            expect($slowJobs[1]->jobId)->toBe('balanced-job');
            expect($slowJobs[2]->jobId)->toBe('medium-job');
        });

        it('identifies memory-intensive jobs correctly', function () {
            $memoryJobs = $this->metricsManager->getTopMemoryJobs(3);

            expect(count($memoryJobs))->toBe(3);
            expect($memoryJobs[0]->jobId)->toBe('memory-heavy');
            expect($memoryJobs[1]->jobId)->toBe('balanced-job');
            expect($memoryJobs[2]->jobId)->toBe('medium-job');
        });

        it('respects limit parameter for top jobs', function () {
            $limitedSlowJobs = $this->metricsManager->getTopSlowJobs(2);
            expect(count($limitedSlowJobs))->toBe(2);

            $limitedMemoryJobs = $this->metricsManager->getTopMemoryJobs(1);
            expect(count($limitedMemoryJobs))->toBe(1);
        });
    });

    describe('Queue Filtering and Analysis', function () {
        beforeEach(function () {
            // This would require modifying the mock to support different queues
            // For now, we'll test the interface
        });

        it('can retrieve jobs by queue', function () {
            $this->metricsManager->recordJobExecution('email-1', 1000.0, 1024 * 1024);
            $this->metricsManager->recordJobExecution('email-2', 2000.0, 2048 * 1024);

            $queueJobs = $this->metricsManager->getJobsByQueue('default-queue');
            expect(count($queueJobs))->toBe(2);
        });

        it('handles non-existent queue filtering', function () {
            $emptyQueue = $this->metricsManager->getJobsByQueue('non-existent-queue');
            expect($emptyQueue)->toBe([]);
        });
    });
});
