<?php

declare(strict_types=1);

namespace App\Framework\Reflection\Async;

use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\DateTime\Clock;
use App\Framework\Reflection\ReflectionProvider;

/**
 * Asynchronous reflection processor for non-blocking operations
 */
final class AsyncReflectionProcessor
{
    /**
     * @var array<string, array<string, mixed>>
     */
    private array $pendingOperations = [];

    public function __construct(
        private readonly ReflectionProvider $reflectionProvider,
        private readonly Clock $clock
    ) {
    }

    /**
     * Queue class reflection for async processing
     */
    public function queueClassReflection(ClassName $className): string
    {
        $operationId = uniqid('reflection_', true);

        $this->pendingOperations[$operationId] = [
            'type' => 'class',
            'className' => $className,
            'status' => 'pending',
            'queued_at' => $this->clock->time()->toFloat(),
        ];

        return $operationId;
    }

    /**
     * Process pending operations in background
     */
    public function processPendingOperations(): void
    {
        foreach ($this->pendingOperations as $operationId => &$operation) {
            if ($operation['status'] === 'pending') {
                try {
                    $operation['status'] = 'processing';
                    $operation['started_at'] = $this->clock->time()->toFloat();

                    match ($operation['type']) {
                        'class' => $this->processClassReflection($operation),
                        default => throw new \InvalidArgumentException("Unknown operation type: {$operation['type']}")
                    };

                    $operation['status'] = 'completed';
                    $operation['completed_at'] = $this->clock->time()->toFloat();
                } catch (\Throwable $e) {
                    $operation['status'] = 'failed';
                    $operation['error'] = $e->getMessage();
                    $operation['failed_at'] = $this->clock->time()->toFloat();
                }
            }
        }
    }

    /**
     * @param array<string, mixed> $operation
     */
    private function processClassReflection(array &$operation): void
    {
        $className = ClassName::create($operation['className']);

        // Pre-load commonly needed reflection data
        $class = $this->reflectionProvider->getClass($className);
        $methods = $this->reflectionProvider->getMethods($className);
        $attributes = $this->reflectionProvider->getAttributes($className);

        $operation['result'] = [
            'class' => $class,
            'methods' => $methods,
            'attributes' => $attributes,
        ];
    }

    /**
     * @return array<string, mixed>|null
     */
    public function getOperationStatus(string $operationId): ?array
    {
        return $this->pendingOperations[$operationId] ?? null;
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    public function getCompletedOperations(): array
    {
        return array_filter(
            $this->pendingOperations,
            static fn (array $op) => $op['status'] === 'completed'
        );
    }
}
