<?php

declare(strict_types=1);

namespace App\Framework\Health\Checks;

use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Health\HealthCheckCategory;
use App\Framework\Health\HealthCheckInterface;
use App\Framework\Health\HealthCheckResult;

final readonly class DiskSpaceHealthCheck implements HealthCheckInterface
{
    public function __construct(
        private string $path = '/',
        private int $warningThreshold = 85, // Warn at 85% usage
        private int $criticalThreshold = 95  // Critical at 95% usage
    ) {
    }

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

        try {
            $freeBytes = disk_free_space($this->path);
            $totalBytes = disk_total_space($this->path);

            if ($freeBytes === false || $totalBytes === false) {
                return HealthCheckResult::unhealthy(
                    'Disk Space',
                    'Could not retrieve disk space information',
                    ['path' => $this->path]
                );
            }

            $freeSpace = Byte::fromBytes((int) $freeBytes);
            $totalSpace = Byte::fromBytes((int) $totalBytes);
            $usedSpace = $totalSpace->subtract($freeSpace);
            $usagePercentage = $usedSpace->percentOf($totalSpace);

            $responseTime = Duration::fromSeconds(microtime(true) - $startTime);

            $details = [
                'path' => $this->path,
                'usage_percentage' => $usagePercentage->format(),
                'free_space' => $freeSpace->toHumanReadable(),
                'total_space' => $totalSpace->toHumanReadable(),
                'used_space' => $usedSpace->toHumanReadable(),
                'check_time' => $responseTime->toHumanReadable(),
            ];

            if ($usagePercentage->getValue() >= $this->criticalThreshold) {
                return HealthCheckResult::unhealthy(
                    'Disk Space',
                    "Critically low: {$usagePercentage->format()} used",
                    $details,
                    $responseTime->toMilliseconds()
                );
            }

            if ($usagePercentage->getValue() >= $this->warningThreshold) {
                return HealthCheckResult::warning(
                    'Disk Space',
                    "Warning: {$usagePercentage->format()} used",
                    $details,
                    $responseTime->toMilliseconds()
                );
            }

            return HealthCheckResult::healthy(
                'Disk Space',
                $details,
                $responseTime->toMilliseconds()
            );

        } catch (\Throwable $e) {
            $responseTime = Duration::fromSeconds(microtime(true) - $startTime);

            return HealthCheckResult::unhealthy(
                'Disk Space',
                'Check failed: ' . $e->getMessage(),
                ['path' => $this->path],
                $responseTime->toMilliseconds(),
                $e
            );
        }
    }

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

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

    public function getTimeout(): int
    {
        return 2000; // 2 seconds
    }
}
