<?php

declare(strict_types=1);

namespace App\Framework\Logging\Health;

use App\Framework\Health\HealthCheckCategory;
use App\Framework\Health\HealthCheckInterface;
use App\Framework\Health\HealthCheckResult;
use App\Framework\Health\HealthStatus;
use App\Framework\Logging\Handlers\BufferedLogHandler;
use App\Framework\Logging\Handlers\ResilientLogHandler;
use App\Framework\Logging\LogHandler;
use App\Framework\Performance\Stopwatch;

/**
 * Logging Health Check
 *
 * Prüft die Gesundheit des Logging-Systems:
 * - Handler-Status
 * - Disk Space (für File-Handler)
 * - Circuit Breaker Status
 * - Buffer-Füllstand
 * - Write-Permissions
 */
final class LoggingHealthCheck implements HealthCheckInterface
{
    /**
     * @param LogHandler[] $handlers
     */
    public function __construct(
        private readonly array $handlers,
        private readonly string $logPath,
        private readonly int $minDiskSpaceGb = 5,
        private readonly int $bufferWarningThreshold = 80
    ) {
    }

    public function check(): HealthCheckResult
    {
        $stopwatch = Stopwatch::start();
        $checks = [];
        $overallHealthy = true;
        $degraded = false;

        // Check Disk Space
        $diskCheck = $this->checkDiskSpace();
        $checks['disk_space'] = $diskCheck->toArray();

        if ($diskCheck->status === HealthStatus::UNHEALTHY) {
            $overallHealthy = false;
        } elseif ($diskCheck->status === HealthStatus::DEGRADED) {
            $degraded = true;
        }

        // Check Write Permissions
        $permissionCheck = $this->checkWritePermissions();
        $checks['write_permissions'] = $permissionCheck->toArray();

        if ($permissionCheck->status === HealthStatus::UNHEALTHY) {
            $overallHealthy = false;
        }

        // Check Handlers
        $handlerChecks = $this->checkHandlers();
        $checks['handlers'] = $handlerChecks;

        foreach ($handlerChecks as $handlerCheck) {
            if ($handlerCheck['status'] === 'unhealthy') {
                $overallHealthy = false;
            } elseif ($handlerCheck['status'] === 'degraded') {
                $degraded = true;
            }
        }

        $duration = $stopwatch->stop();
        $status = $overallHealthy ? ($degraded ? HealthStatus::DEGRADED : HealthStatus::HEALTHY) : HealthStatus::UNHEALTHY;

        $message = match($status) {
            HealthStatus::HEALTHY => 'Logging system healthy',
            HealthStatus::DEGRADED => 'Logging system degraded',
            HealthStatus::UNHEALTHY => 'Logging system unhealthy',
        };

        return new HealthCheckResult(
            status: $status,
            componentName: $this->getName(),
            message: $message,
            details: $checks,
            timestamp: new \DateTimeImmutable(),
            duration: $duration->toSeconds()
        );
    }

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

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

    public function getTimeout(): int
    {
        return 5000; // 5 seconds timeout for logging health check
    }

    private function checkDiskSpace(): HealthCheckResult
    {
        if (!file_exists($this->logPath)) {
            return new HealthCheckResult(
                status: HealthStatus::UNHEALTHY,
                componentName: 'disk_space',
                message: 'Log directory does not exist',
                details: ['path' => $this->logPath],
                timestamp: new \DateTimeImmutable()
            );
        }

        $freeSpace = disk_free_space($this->logPath);
        $totalSpace = disk_total_space($this->logPath);

        if ($freeSpace === false || $totalSpace === false) {
            return new HealthCheckResult(
                status: HealthStatus::DEGRADED,
                componentName: 'disk_space',
                message: 'Could not determine disk space',
                details: ['path' => $this->logPath],
                timestamp: new \DateTimeImmutable()
            );
        }

        $freeGb = $freeSpace / (1024 ** 3);
        $totalGb = $totalSpace / (1024 ** 3);
        $usedPercent = (($totalSpace - $freeSpace) / $totalSpace) * 100;

        $details = [
            'free_gb' => round($freeGb, 2),
            'total_gb' => round($totalGb, 2),
            'used_percent' => round($usedPercent, 2),
            'path' => $this->logPath,
        ];

        if ($freeGb < $this->minDiskSpaceGb) {
            return new HealthCheckResult(
                status: HealthStatus::UNHEALTHY,
                componentName: 'disk_space',
                message: sprintf('Low disk space: %.2f GB free', $freeGb),
                details: $details,
                timestamp: new \DateTimeImmutable()
            );
        }

        if ($usedPercent > 90) {
            return new HealthCheckResult(
                status: HealthStatus::DEGRADED,
                componentName: 'disk_space',
                message: sprintf('High disk usage: %.1f%%', $usedPercent),
                details: $details,
                timestamp: new \DateTimeImmutable()
            );
        }

        return new HealthCheckResult(
            status: HealthStatus::HEALTHY,
            componentName: 'disk_space',
            message: 'Sufficient disk space',
            details: $details,
            timestamp: new \DateTimeImmutable()
        );
    }

    private function checkWritePermissions(): HealthCheckResult
    {
        if (!is_dir($this->logPath)) {
            return new HealthCheckResult(
                status: HealthStatus::UNHEALTHY,
                componentName: 'write_permissions',
                message: 'Log directory does not exist',
                details: ['path' => $this->logPath],
                timestamp: new \DateTimeImmutable()
            );
        }

        if (!is_writable($this->logPath)) {
            return new HealthCheckResult(
                status: HealthStatus::UNHEALTHY,
                componentName: 'write_permissions',
                message: 'Log directory not writable',
                details: ['path' => $this->logPath],
                timestamp: new \DateTimeImmutable()
            );
        }

        return new HealthCheckResult(
            status: HealthStatus::HEALTHY,
            componentName: 'write_permissions',
            message: 'Write permissions OK',
            details: [
                'path' => $this->logPath,
                'writable' => true,
            ],
            timestamp: new \DateTimeImmutable()
        );
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function checkHandlers(): array
    {
        $results = [];

        foreach ($this->handlers as $index => $handler) {
            $results[] = $this->checkHandler($handler, $index);
        }

        return $results;
    }

    /**
     * @return array<string, mixed>
     */
    private function checkHandler(LogHandler $handler, int $index): array
    {
        $name = $this->getHandlerName($handler, $index);
        $result = [
            'name' => $name,
            'type' => get_class($handler),
        ];

        // Check ResilientLogHandler
        if ($handler instanceof ResilientLogHandler) {
            $isHealthy = $handler->isHealthy();
            $result['status'] = $isHealthy ? 'healthy' : 'degraded';
            $result['circuit_breaker_state'] = $handler->getCircuitBreakerState();

            if (!$isHealthy) {
                $result['message'] = 'Circuit breaker open';
            }

            return $result;
        }

        // Check BufferedLogHandler
        if ($handler instanceof BufferedLogHandler) {
            $bufferSize = $handler->getBufferSize();
            $result['buffer_size'] = $bufferSize;

            // Assuming max buffer size is accessible or known
            // For now, use threshold percentage
            if ($bufferSize > $this->bufferWarningThreshold) {
                $result['status'] = 'degraded';
                $result['message'] = 'High buffer usage';
            } else {
                $result['status'] = 'healthy';
            }

            return $result;
        }

        // Check HealthCheckInterface
        if ($handler instanceof \App\Framework\Health\HealthCheckInterface) {
            $healthCheck = $handler->check();
            $result['status'] = $healthCheck->status->value;
            $result['message'] = $healthCheck->message;
            $result['details'] = $healthCheck->details;

            return $result;
        }

        // Default: assume healthy
        $result['status'] = 'healthy';
        return $result;
    }

    private function getHandlerName(LogHandler $handler, int $index): string
    {
        if ($handler instanceof \App\Framework\Health\HealthCheckInterface) {
            return $handler->getName();
        }

        $className = get_class($handler);
        $shortName = substr($className, strrpos($className, '\\') + 1);

        return sprintf('%s_%d', $shortName, $index);
    }
}
