<?php

declare(strict_types=1);

namespace App\Framework\Deployment\Ssl\HealthChecks;

use App\Framework\Config\Environment;
use App\Framework\Deployment\Ssl\Services\SslCertificateService;
use App\Framework\Deployment\Ssl\ValueObjects\SslConfiguration;
use App\Framework\Health\HealthCheckCategory;
use App\Framework\Health\HealthCheckInterface;
use App\Framework\Health\HealthCheckResult;

/**
 * SSL Certificate Health Check - Monitor SSL certificate status
 */
final readonly class SslCertificateHealthCheck implements HealthCheckInterface
{
    public function __construct(
        private SslCertificateService $sslService,
        private Environment $environment
    ) {}

    public function check(): HealthCheckResult
    {
        $startTime = microtime(true);

        try {
            $config = SslConfiguration::fromEnvironment($this->environment);

            $status = $this->sslService->getStatus(
                $config->domain,
                $config->certbotConfDir->toString()
            );

            $responseTime = (microtime(true) - $startTime) * 1000;

            // Certificate doesn't exist
            if (!$status->exists) {
                return HealthCheckResult::unhealthy(
                    operation: 'SSL Certificate Check',
                    reason: 'Certificate not found',
                    details: [
                        'domain' => $config->domain->value,
                        'certificate_dir' => $config->certbotConfDir->toString(),
                    ],
                    responseTimeMs: $responseTime
                );
            }

            // Certificate is expired
            if ($status->isExpired) {
                return HealthCheckResult::unhealthy(
                    operation: 'SSL Certificate Check',
                    reason: 'Certificate has expired',
                    details: [
                        'domain' => $config->domain->value,
                        'expired_date' => $status->notAfter?->format('Y-m-d H:i:s'),
                        'days_since_expiry' => abs($status->daysUntilExpiry ?? 0),
                    ],
                    responseTimeMs: $responseTime
                );
            }

            // Certificate is expiring soon (warning)
            if ($status->isExpiring) {
                return HealthCheckResult::warning(
                    operation: 'SSL Certificate Check',
                    reason: "Certificate expires in {$status->daysUntilExpiry} days",
                    details: [
                        'domain' => $config->domain->value,
                        'expiry_date' => $status->notAfter?->format('Y-m-d H:i:s'),
                        'days_until_expiry' => $status->daysUntilExpiry,
                        'issuer' => $status->issuer,
                        'subject' => $status->subject,
                    ],
                    responseTimeMs: $responseTime
                );
            }

            // Certificate is invalid
            if (!$status->isValid) {
                return HealthCheckResult::unhealthy(
                    operation: 'SSL Certificate Check',
                    reason: 'Certificate is invalid',
                    details: [
                        'domain' => $config->domain->value,
                        'errors' => $status->errors,
                        'valid_from' => $status->notBefore?->format('Y-m-d H:i:s'),
                        'valid_until' => $status->notAfter?->format('Y-m-d H:i:s'),
                    ],
                    responseTimeMs: $responseTime
                );
            }

            // Certificate is healthy
            return HealthCheckResult::healthy(
                operation: 'SSL Certificate Check',
                details: [
                    'domain' => $config->domain->value,
                    'valid_until' => $status->notAfter?->format('Y-m-d H:i:s'),
                    'days_until_expiry' => $status->daysUntilExpiry,
                    'issuer' => $status->issuer,
                    'subject' => $status->subject,
                    'health_status' => $status->getHealthStatus(),
                ],
                responseTimeMs: $responseTime
            );

        } catch (\Exception $e) {
            $responseTime = (microtime(true) - $startTime) * 1000;

            return HealthCheckResult::unhealthy(
                operation: 'SSL Certificate Check',
                reason: 'Health check failed',
                details: [],
                responseTimeMs: $responseTime,
                exception: $e
            );
        }
    }

    public function getName(): string
    {
        return 'SSL Certificate';
    }

    public function getCategory(): HealthCheckCategory
    {
        return HealthCheckCategory::SECURITY;
    }

    public function getTimeout(): int
    {
        return 5000; // 5 seconds
    }
}
