<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Monitoring;

use Doctrine\DBAL\Connection;
use Redis;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Throwable;

/**
 * Centralized infrastructure health checking service.
 *
 * Used by both HealthCheckController and HealthMetricsCollector
 * to avoid code duplication (DRY principle).
 *
 * @see Story 1.8 - T7: Health Check Endpoint
 */
final readonly class InfrastructureHealthChecker implements InfrastructureHealthCheckerInterface
{
    public function __construct(
        private Connection $connection,
        private HttpClientInterface $httpClient,
        private string $redisUrl = 'redis://redis:6379',
        private string $rabbitmqManagementUrl = 'http://rabbitmq:15672',
        private string $rabbitmqUser = 'guest',
        private string $rabbitmqPassword = 'guest',
    ) {
    }

    public function checkPostgres(): bool
    {
        try {
            $this->connection->executeQuery('SELECT 1');

            return true;
        } catch (Throwable) {
            return false;
        }
    }

    public function checkRedis(): bool
    {
        try {
            $parsed = parse_url($this->redisUrl);
            $host = $parsed['host'] ?? 'redis';
            $port = $parsed['port'] ?? 6379;

            $redis = new Redis();
            $redis->connect($host, $port, 2.0); // 2 second timeout

            $pong = $redis->ping();
            $redis->close();

            return $pong === true || $pong === '+PONG' || $pong === 'PONG';
        } catch (Throwable) {
            return false;
        }
    }

    public function checkRabbitMQ(): bool
    {
        try {
            // Check RabbitMQ via management API health check endpoint
            $response = $this->httpClient->request('GET', $this->rabbitmqManagementUrl . '/api/health/checks/alarms', [
                'auth_basic' => [$this->rabbitmqUser, $this->rabbitmqPassword],
                'timeout' => 2,
            ]);

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $data = $response->toArray();

            // RabbitMQ returns {"status":"ok"} when healthy
            return ($data['status'] ?? '') === 'ok';
        } catch (Throwable) {
            return false;
        }
    }

    /**
     * Check all services and return aggregated status.
     *
     * @return array{postgres: bool, redis: bool, rabbitmq: bool}
     */
    public function checkAll(): array
    {
        return [
            'postgres' => $this->checkPostgres(),
            'redis' => $this->checkRedis(),
            'rabbitmq' => $this->checkRabbitMQ(),
        ];
    }
}
