<?php

declare(strict_types=1);

use App\Application\LiveComponents\Dashboard\WorkerHealthComponent;
use App\Application\LiveComponents\Dashboard\WorkerHealthState;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\Queue\Services\WorkerRegistry;
use App\Framework\Queue\Entities\Worker;
use App\Framework\Queue\ValueObjects\WorkerId;
use App\Framework\Core\ValueObjects\Timestamp;

describe('WorkerHealthComponent', function () {
    beforeEach(function () {
        $this->workerRegistry = Mockery::mock(WorkerRegistry::class);
        $this->componentId = ComponentId::create('worker-health', 'test');
        $this->initialState = WorkerHealthState::empty();
    });

    afterEach(function () {
        Mockery::close();
    });

    it('polls and updates state with worker health data', function () {
        $now = Timestamp::now();
        $oneMinuteAgo = $now->sub(Duration::fromSeconds(60));

        $worker1 = new Worker(
            id: WorkerId::generate(),
            hostname: 'server-01',
            processId: 12345,
            startedAt: $oneMinuteAgo,
            lastHeartbeat: $now,
            status: 'active',
            currentJobs: 2,
            maxJobs: 10,
            memoryUsageMb: 128.5,
            cpuUsage: 45.2
        );

        $worker2 = new Worker(
            id: WorkerId::generate(),
            hostname: 'server-02',
            processId: 67890,
            startedAt: $oneMinuteAgo,
            lastHeartbeat: $now->sub(Duration::fromMinutes(5)), // Unhealthy - old heartbeat
            status: 'active',
            currentJobs: 0,
            maxJobs: 10,
            memoryUsageMb: 64.0,
            cpuUsage: 98.5 // Unhealthy - high CPU
        );

        $this->workerRegistry->shouldReceive('findActiveWorkers')
            ->once()
            ->andReturn([$worker1, $worker2]);

        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $this->initialState,
            workerRegistry: $this->workerRegistry
        );

        $newState = $component->poll();

        expect($newState)->toBeInstanceOf(WorkerHealthState::class);
        expect($newState->activeWorkers)->toBe(2);
        expect($newState->totalWorkers)->toBe(2);
        expect($newState->jobsInProgress)->toBe(2); // Only worker1 has jobs
        expect($newState->workerDetails)->toHaveCount(2);

        // Worker 1 should be healthy
        expect($newState->workerDetails[0]['healthy'])->toBeTrue();
        expect($newState->workerDetails[0]['hostname'])->toBe('server-01');

        // Worker 2 should be unhealthy
        expect($newState->workerDetails[1]['healthy'])->toBeFalse();
    });

    it('identifies healthy workers correctly', function () {
        $now = Timestamp::now();

        $healthyWorker = new Worker(
            id: WorkerId::generate(),
            hostname: 'healthy-server',
            processId: 11111,
            startedAt: $now->sub(Duration::fromMinutes(5)),
            lastHeartbeat: $now->sub(Duration::fromSeconds(30)), // Recent heartbeat
            status: 'active',
            currentJobs: 5,
            maxJobs: 10,
            memoryUsageMb: 100.0,
            cpuUsage: 50.0 // Normal CPU
        );

        $this->workerRegistry->shouldReceive('findActiveWorkers')
            ->once()
            ->andReturn([$healthyWorker]);

        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $this->initialState,
            workerRegistry: $this->workerRegistry
        );

        $newState = $component->poll();

        expect($newState->workerDetails[0]['healthy'])->toBeTrue();
    });

    it('identifies unhealthy workers by stale heartbeat', function () {
        $now = Timestamp::now();

        $staleWorker = new Worker(
            id: WorkerId::generate(),
            hostname: 'stale-server',
            processId: 22222,
            startedAt: $now->sub(Duration::fromMinutes(10)),
            lastHeartbeat: $now->sub(Duration::fromMinutes(3)), // Stale heartbeat
            status: 'active',
            currentJobs: 2,
            maxJobs: 10,
            memoryUsageMb: 80.0,
            cpuUsage: 30.0
        );

        $this->workerRegistry->shouldReceive('findActiveWorkers')
            ->once()
            ->andReturn([$staleWorker]);

        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $this->initialState,
            workerRegistry: $this->workerRegistry
        );

        $newState = $component->poll();

        expect($newState->workerDetails[0]['healthy'])->toBeFalse();
    });

    it('identifies unhealthy workers by high CPU', function () {
        $now = Timestamp::now();

        $highCpuWorker = new Worker(
            id: WorkerId::generate(),
            hostname: 'high-cpu-server',
            processId: 33333,
            startedAt: $now->sub(Duration::fromMinutes(5)),
            lastHeartbeat: $now, // Recent heartbeat
            status: 'active',
            currentJobs: 8,
            maxJobs: 10,
            memoryUsageMb: 200.0,
            cpuUsage: 96.5 // High CPU
        );

        $this->workerRegistry->shouldReceive('findActiveWorkers')
            ->once()
            ->andReturn([$highCpuWorker]);

        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $this->initialState,
            workerRegistry: $this->workerRegistry
        );

        $newState = $component->poll();

        expect($newState->workerDetails[0]['healthy'])->toBeFalse();
    });

    it('has correct poll interval', function () {
        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $this->initialState,
            workerRegistry: $this->workerRegistry
        );

        expect($component->getPollInterval())->toBe(5000);
    });

    it('returns correct render data', function () {
        $workerDetails = [
            [
                'id' => 'worker-1',
                'hostname' => 'server-01',
                'healthy' => true,
                'jobs' => 5,
            ],
        ];

        $state = new WorkerHealthState(
            activeWorkers: 1,
            totalWorkers: 1,
            jobsInProgress: 5,
            workerDetails: $workerDetails,
            lastUpdated: '2024-01-15 12:00:00'
        );

        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $state,
            workerRegistry: $this->workerRegistry
        );

        $renderData = $component->getRenderData();

        expect($renderData->templatePath)->toBe('livecomponent-worker-health');
        expect($renderData->data)->toHaveKey('componentId');
        expect($renderData->data)->toHaveKey('pollInterval');
        expect($renderData->data['pollInterval'])->toBe(5000);
        expect($renderData->data['activeWorkers'])->toBe(1);
        expect($renderData->data['jobsInProgress'])->toBe(5);
    });

    it('handles no active workers', function () {
        $this->workerRegistry->shouldReceive('findActiveWorkers')
            ->once()
            ->andReturn([]);

        $component = new WorkerHealthComponent(
            id: $this->componentId,
            state: $this->initialState,
            workerRegistry: $this->workerRegistry
        );

        $newState = $component->poll();

        expect($newState->activeWorkers)->toBe(0);
        expect($newState->totalWorkers)->toBe(0);
        expect($newState->jobsInProgress)->toBe(0);
        expect($newState->workerDetails)->toBe([]);
    });
});
