<?php

declare(strict_types=1);

namespace App\Framework\Health;

use App\Framework\Health\ValueObjects\HealthDetails;
use App\Framework\Health\ValueObjects\HealthMessage;
use App\Framework\Health\ValueObjects\ResponseTime;

final readonly class HealthCheckResult
{
    public function __construct(
        public HealthStatus $status,
        public HealthMessage $message,
        public HealthDetails $details,
        public ?ResponseTime $responseTime = null,
        public ?\Throwable $exception = null
    ) {
    }

    public function isHealthy(): bool
    {
        return $this->status === HealthStatus::HEALTHY;
    }

    public function isWarning(): bool
    {
        return $this->status === HealthStatus::WARNING;
    }

    public function isUnhealthy(): bool
    {
        return $this->status === HealthStatus::UNHEALTHY;
    }

    public function toArray(): array
    {
        return [
            'status' => $this->status->value,
            'message' => $this->message->toString(),
            'message_formatted' => $this->message->toFormattedString(),
            'message_type' => $this->message->type->value,
            'details' => $this->details->toArray(),
            'response_time_ms' => $this->responseTime?->duration->toMilliseconds(),
            'response_time_formatted' => $this->responseTime?->toString(),
            'response_time_level' => $this->responseTime?->getPerformanceLevel()->value,
            'error' => $this->exception ? [
                'message' => $this->exception->getMessage(),
                'code' => $this->exception->getCode(),
                'type' => get_class($this->exception),
            ] : null,
        ];
    }

    public static function healthy(string $operation, array $details = [], ?float $responseTimeMs = null): self
    {
        return new self(
            HealthStatus::HEALTHY,
            HealthMessage::success($operation),
            HealthDetails::fromArray($details),
            $responseTimeMs !== null ? ResponseTime::fromMilliseconds($responseTimeMs) : null
        );
    }

    public static function warning(string $operation, string $reason, array $details = [], ?float $responseTimeMs = null): self
    {
        return new self(
            HealthStatus::WARNING,
            HealthMessage::warning($operation, $reason),
            HealthDetails::fromArray($details),
            $responseTimeMs !== null ? ResponseTime::fromMilliseconds($responseTimeMs) : null
        );
    }

    public static function unhealthy(string $operation, string $reason, array $details = [], ?float $responseTimeMs = null, ?\Throwable $exception = null): self
    {
        $detailsObj = $exception !== null
            ? HealthDetails::fromArray($details)->merge(HealthDetails::forError($exception))
            : HealthDetails::fromArray($details);

        return new self(
            HealthStatus::UNHEALTHY,
            HealthMessage::failure($operation, $reason),
            $detailsObj,
            $responseTimeMs !== null ? ResponseTime::fromMilliseconds($responseTimeMs) : null,
            $exception
        );
    }

    // Additional factory methods for common cases
    public static function timeout(string $operation, float $timeoutMs, array $details = []): self
    {
        return new self(
            HealthStatus::UNHEALTHY,
            HealthMessage::timeout($operation, $timeoutMs),
            HealthDetails::fromArray($details),
            ResponseTime::fromMilliseconds($timeoutMs)
        );
    }

    public static function degraded(string $operation, string $reason, array $details = [], ?float $responseTimeMs = null): self
    {
        return new self(
            HealthStatus::WARNING,
            HealthMessage::degraded($operation, $reason),
            HealthDetails::fromArray($details),
            $responseTimeMs !== null ? ResponseTime::fromMilliseconds($responseTimeMs) : null
        );
    }

    // Advanced factory method with Value Objects
    public static function create(
        HealthStatus $status,
        HealthMessage $message,
        HealthDetails $details,
        ?ResponseTime $responseTime = null,
        ?\Throwable $exception = null
    ): self {
        return new self($status, $message, $details, $responseTime, $exception);
    }
}
