<?php

declare(strict_types=1);

namespace App\Framework\Deployment\Pipeline\Stages;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Deployment\Docker\Services\DockerComposeService;
use App\Framework\Deployment\Pipeline\ValueObjects\DeploymentEnvironment;
use App\Framework\Deployment\Pipeline\ValueObjects\PipelineStage;
use App\Framework\Deployment\Pipeline\ValueObjects\StageResult;
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Logging\Logger;

/**
 * Health Check Stage
 *
 * Verifies that deployed containers are healthy and running.
 */
final readonly class HealthCheckStage implements PipelineStageInterface
{
    public function __construct(
        private DockerComposeService $composeService,
        private Logger $logger
    ) {}

    public function getStage(): PipelineStage
    {
        return PipelineStage::HEALTH_CHECK;
    }

    public function execute(DeploymentEnvironment $environment): StageResult
    {
        $startTime = microtime(true);

        $this->logger->info('Running health checks', [
            'environment' => $environment->value
        ]);

        try {
            $composeFile = $this->getComposeFile($environment);

            // Get service status
            $services = $this->composeService->ps($composeFile);

            if (empty($services)) {
                throw new \RuntimeException('No services found');
            }

            // Check if all services are running
            $failedServices = [];
            foreach ($services as $service) {
                if (!$service->isRunning) {
                    $failedServices[] = $service->name;
                }
            }

            if (!empty($failedServices)) {
                throw new \RuntimeException(
                    'Services not running: ' . implode(', ', $failedServices)
                );
            }

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

            return StageResult::success(
                stage: $this->getStage(),
                duration: $duration,
                output: sprintf('All %d services are healthy', count($services))
            );

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

            $this->logger->error('Health check failed', [
                'error' => $e->getMessage()
            ]);

            return StageResult::failure(
                stage: $this->getStage(),
                duration: $duration,
                error: $e->getMessage()
            );
        }
    }

    public function canRollback(): bool
    {
        return false;
    }

    public function rollback(DeploymentEnvironment $environment): StageResult
    {
        throw new \LogicException('Health check stage does not support rollback');
    }

    public function getDescription(): string
    {
        return $this->getStage()->getDescription();
    }

    public function shouldSkip(DeploymentEnvironment $environment): bool
    {
        return false; // Always check health
    }

    private function getComposeFile(DeploymentEnvironment $environment): FilePath
    {
        return match ($environment) {
            DeploymentEnvironment::DEVELOPMENT => FilePath::fromString('/var/www/html/docker-compose.yml'),
            DeploymentEnvironment::STAGING => FilePath::fromString('/var/www/html/docker-compose.staging.yml'),
            DeploymentEnvironment::PRODUCTION => FilePath::fromString('/var/www/html/docker-compose.prod.yml'),
        };
    }
}
