<?php

declare(strict_types=1);

namespace App\Framework\ErrorBoundaries\Async;

use App\Framework\Core\ValueObjects\Percentage;
use Throwable;

/**
 * Result object for async bulk operations
 */
final readonly class AsyncBulkResult
{
    public function __construct(
        public array $results,
        public array $errors,
        public int $totalOperations,
        public int $successfulOperations,
    ) {
    }

    /**
     * Get success rate as percentage
     */
    public function getSuccessRate(): Percentage
    {
        if ($this->totalOperations === 0) {
            return Percentage::fromFloat(0.0);
        }

        return Percentage::fromFloat($this->successfulOperations / $this->totalOperations);
    }

    /**
     * Get error rate as percentage
     */
    public function getErrorRate(): Percentage
    {
        if ($this->totalOperations === 0) {
            return Percentage::fromFloat(0.0);
        }

        return Percentage::fromFloat($this->getErrorCount() / $this->totalOperations);
    }

    /**
     * Get number of errors
     */
    public function getErrorCount(): int
    {
        return count($this->errors);
    }

    /**
     * Check if any operations succeeded
     */
    public function hasSuccesses(): bool
    {
        return $this->successfulOperations > 0;
    }

    /**
     * Check if any operations failed
     */
    public function hasErrors(): bool
    {
        return count($this->errors) > 0;
    }

    /**
     * Check if all operations succeeded
     */
    public function isCompleteSuccess(): bool
    {
        return $this->successfulOperations === $this->totalOperations;
    }

    /**
     * Check if all operations failed
     */
    public function isCompleteFailure(): bool
    {
        return count($this->errors) === $this->totalOperations;
    }

    /**
     * Get all successful results
     */
    public function getSuccessfulResults(): array
    {
        return $this->results;
    }

    /**
     * Get all errors
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * Get error by key
     */
    public function getError(string $key): ?Throwable
    {
        return $this->errors[$key] ?? null;
    }

    /**
     * Get result by key
     */
    public function getResult(string $key): mixed
    {
        return $this->results[$key] ?? null;
    }

    /**
     * Check if key has error
     */
    public function hasError(string $key): bool
    {
        return isset($this->errors[$key]);
    }

    /**
     * Check if key has result
     */
    public function hasResult(string $key): bool
    {
        return isset($this->results[$key]);
    }

    /**
     * Get summary statistics
     */
    public function getSummary(): array
    {
        return [
            'total_operations' => $this->totalOperations,
            'successful_operations' => $this->successfulOperations,
            'failed_operations' => $this->getErrorCount(),
            'success_rate' => $this->getSuccessRate()->toFloat(),
            'error_rate' => $this->getErrorRate()->toFloat(),
            'is_complete_success' => $this->isCompleteSuccess(),
            'is_complete_failure' => $this->isCompleteFailure(),
            'has_partial_success' => $this->hasSuccesses() && $this->hasErrors(),
        ];
    }

    /**
     * Convert to array
     */
    public function toArray(): array
    {
        return [
            'results' => $this->results,
            'errors' => array_map(
                fn (Throwable $e) => [
                    'class' => $e::class,
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                ],
                $this->errors
            ),
            'summary' => $this->getSummary(),
        ];
    }
}
