<?php

declare(strict_types=1);

namespace App\Framework\Mcp\Core\ValueObjects;

/**
 * Execution Result Value Object
 *
 * Contains the result of a task execution including performance metrics.
 */
final readonly class ExecutionResult
{
    public function __construct(
        public string $taskId,
        public bool $success,
        public mixed $result,
        public ?string $error,
        public float $executionTime,
        public int $memoryUsage,
        public bool $fromCache = false,
        public array $metadata = []
    ) {
    }

    public function toArray(): array
    {
        return [
            'task_id' => $this->taskId,
            'success' => $this->success,
            'result' => $this->result,
            'error' => $this->error,
            'execution_time' => $this->executionTime,
            'execution_time_formatted' => $this->formatExecutionTime(),
            'memory_usage' => $this->memoryUsage,
            'memory_usage_formatted' => $this->formatMemoryUsage(),
            'from_cache' => $this->fromCache,
            'metadata' => $this->metadata,
            'performance_grade' => $this->getPerformanceGrade(),
        ];
    }

    public function isSuccessful(): bool
    {
        return $this->success;
    }

    public function hasError(): bool
    {
        return $this->error !== null;
    }

    public function getPerformanceGrade(): string
    {
        if (! $this->success) {
            return 'F';
        }

        if ($this->fromCache) {
            return 'A+'; // Cache hits are excellent
        }

        $score = $this->calculatePerformanceScore();

        return match (true) {
            $score >= 90 => 'A+',
            $score >= 85 => 'A',
            $score >= 80 => 'B+',
            $score >= 75 => 'B',
            $score >= 70 => 'C+',
            $score >= 65 => 'C',
            $score >= 60 => 'D',
            default => 'F'
        };
    }

    private function calculatePerformanceScore(): float
    {
        $timeScore = $this->calculateTimeScore() * 0.6; // 60% weight
        $memoryScore = $this->calculateMemoryScore() * 0.4; // 40% weight

        return $timeScore + $memoryScore;
    }

    private function calculateTimeScore(): float
    {
        return match (true) {
            $this->executionTime <= 0.5 => 100,
            $this->executionTime <= 1.0 => 90,
            $this->executionTime <= 2.0 => 80,
            $this->executionTime <= 5.0 => 60,
            $this->executionTime <= 10.0 => 30,
            default => 10
        };
    }

    private function calculateMemoryScore(): float
    {
        $memoryMB = $this->memoryUsage / (1024 * 1024);

        return match (true) {
            $memoryMB <= 10 => 100,
            $memoryMB <= 25 => 90,
            $memoryMB <= 50 => 80,
            $memoryMB <= 100 => 60,
            $memoryMB <= 200 => 30,
            default => 10
        };
    }

    private function formatExecutionTime(): string
    {
        if ($this->executionTime < 0.001) {
            return round($this->executionTime * 1000000, 1) . ' μs';
        }

        if ($this->executionTime < 1.0) {
            return round($this->executionTime * 1000, 1) . ' ms';
        }

        return round($this->executionTime, 3) . ' s';
    }

    private function formatMemoryUsage(): string
    {
        if ($this->memoryUsage === 0) {
            return '0 B';
        }

        $units = ['B', 'KB', 'MB', 'GB'];
        $unitIndex = 0;
        $value = $this->memoryUsage;

        while ($value >= 1024 && $unitIndex < count($units) - 1) {
            $value /= 1024;
            $unitIndex++;
        }

        return round($value, 2) . ' ' . $units[$unitIndex];
    }
}
