<?php

declare(strict_types=1);

namespace App\Framework\Process\ValueObjects\Health;

/**
 * Aggregierter Health Report.
 */
final readonly class HealthReport
{
    /**
     * @param HealthCheck[] $checks
     */
    public function __construct(
        public HealthStatus $overallStatus,
        public array $checks,
        public \DateTimeImmutable $timestamp
    ) {
    }

    /**
     * Erstellt einen Health Report aus Checks.
     *
     * @param HealthCheck[] $checks
     */
    public static function fromChecks(array $checks): self
    {
        $overallStatus = self::determineOverallStatus($checks);

        return new self(
            overallStatus: $overallStatus,
            checks: $checks,
            timestamp: new \DateTimeImmutable()
        );
    }

    /**
     * Bestimmt den Overall Status basierend auf den Checks.
     *
     * @param HealthCheck[] $checks
     */
    private static function determineOverallStatus(array $checks): HealthStatus
    {
        $hasUnhealthy = false;
        $hasDegraded = false;

        foreach ($checks as $check) {
            if ($check->status === HealthStatus::UNHEALTHY) {
                $hasUnhealthy = true;
            } elseif ($check->status === HealthStatus::DEGRADED) {
                $hasDegraded = true;
            }
        }

        if ($hasUnhealthy) {
            return HealthStatus::UNHEALTHY;
        }

        if ($hasDegraded) {
            return HealthStatus::DEGRADED;
        }

        return HealthStatus::HEALTHY;
    }

    /**
     * Gibt die Anzahl der Checks pro Status zurück.
     *
     * @return array{healthy: int, degraded: int, unhealthy: int}
     */
    public function getStatusCounts(): array
    {
        $counts = [
            'healthy' => 0,
            'degraded' => 0,
            'unhealthy' => 0,
        ];

        foreach ($this->checks as $check) {
            $counts[$check->status->value]++;
        }

        return $counts;
    }

    /**
     * Gibt nur unhealthy Checks zurück.
     *
     * @return HealthCheck[]
     */
    public function getUnhealthyChecks(): array
    {
        return array_filter(
            $this->checks,
            fn (HealthCheck $check) => $check->status === HealthStatus::UNHEALTHY
        );
    }

    /**
     * Gibt nur degraded Checks zurück.
     *
     * @return HealthCheck[]
     */
    public function getDegradedChecks(): array
    {
        return array_filter(
            $this->checks,
            fn (HealthCheck $check) => $check->status === HealthStatus::DEGRADED
        );
    }

    /**
     * Konvertiert zu Array.
     *
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'overall_status' => $this->overallStatus->value,
            'overall_description' => $this->overallStatus->getDescription(),
            'timestamp' => $this->timestamp->format('Y-m-d H:i:s'),
            'checks' => array_map(fn (HealthCheck $c) => $c->toArray(), $this->checks),
            'status_counts' => $this->getStatusCounts(),
        ];
    }
}
