<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\Dashboard;

use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\Contracts\Pollable;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;
use App\Framework\Queue\Services\WorkerRegistry;

/**
 * Worker Health Monitoring LiveComponent
 *
 * Displays real-time worker health status:
 * - Active vs total workers
 * - Jobs currently in progress
 * - Individual worker details (heartbeat, job count)
 * - Worker health indicators
 *
 * Polls every 5 seconds for real-time monitoring.
 */
#[LiveComponent('worker-health')]
final readonly class WorkerHealthComponent implements LiveComponentContract, Pollable
{
    public function __construct(
        public ComponentId $id,
        public WorkerHealthState $state,
        private WorkerRegistry $workerRegistry
    ) {}

    public function getRenderData(): ComponentRenderData
    {
        // Initial poll if state is empty (lastUpdated is empty string)
        $state = $this->state->lastUpdated === ''
            ? $this->poll()
            : $this->state;

        return new ComponentRenderData(
            templatePath: 'livecomponent-worker-health',
            data: [
                // LiveComponent integration
                'componentId' => $this->id->toString(),
                'stateJson' => json_encode($state->toArray()),
                'pollInterval' => $this->getPollInterval(),

                // Component data
                'activeWorkers' => $state->activeWorkers,
                'totalWorkers' => $state->totalWorkers,
                'jobsInProgress' => $state->jobsInProgress,
                'workerDetails' => $state->workerDetails,
                'lastUpdated' => $state->lastUpdated,
            ]
        );
    }

    #[Action]
    public function poll(): WorkerHealthState
    {
        // Get all active workers
        $activeWorkers = $this->workerRegistry->findActiveWorkers();
        $totalWorkers = count($activeWorkers);

        $jobsInProgress = 0;
        $workerDetails = [];

        foreach ($activeWorkers as $worker) {
            $jobsInProgress += $worker->currentJobs;

            // Build worker detail array
            $workerDetails[$worker->id->toString()] = [
                'hostname' => $worker->hostname,
                'processId' => $worker->processId,
                'jobs' => $worker->currentJobs,
                'maxJobs' => $worker->maxJobs,
                'lastHeartbeat' => $worker->lastHeartbeat ?? '',
                'cpuUsage' => $worker->cpuUsage?->getValue() ?? 0.0,
                'memoryUsageMb' => $worker->memoryUsageBytes
                    ? round($worker->memoryUsageBytes->toMegabytes(), 2)
                    : 0.0,
                'healthy' => $this->isWorkerHealthy($worker),
            ];
        }

        return $this->state->withWorkerHealth(
            activeWorkers: $totalWorkers,
            totalWorkers: $totalWorkers,
            jobsInProgress: $jobsInProgress,
            workerDetails: $workerDetails
        );
    }

    public function getPollInterval(): int
    {
        return 5000; // Poll every 5 seconds for worker health monitoring
    }

    /**
     * Check if worker is healthy based on heartbeat and resource usage
     */
    private function isWorkerHealthy($worker): bool
    {
        // Check heartbeat is recent (within 2 minutes)
        if ($worker->lastHeartbeat === null) {
            return false;
        }

        $heartbeatTime = strtotime($worker->lastHeartbeat);
        $now = time();
        $heartbeatAge = $now - $heartbeatTime;

        if ($heartbeatAge > 120) { // 2 minutes
            return false;
        }

        // Check CPU and memory aren't critically high
        $cpuUsage = $worker->cpuUsage?->getValue() ?? 0.0;
        if ($cpuUsage > 95.0) {
            return false;
        }

        return true;
    }
}
