<?php

declare(strict_types=1);

namespace Tests\Support;

use App\Framework\LiveComponents\Services\UploadProgressTrackerInterface;
use App\Framework\LiveComponents\ValueObjects\UploadSession;
use App\Framework\LiveComponents\ValueObjects\UploadSessionId;

/**
 * In-Memory Upload Progress Tracker for Testing
 *
 * Records all broadcast events for assertion in tests.
 * Does not require actual SSE infrastructure.
 */
final class InMemoryUploadProgressTracker implements UploadProgressTrackerInterface
{
    /** @var array<array{type: string, session_id: string, user_id: string, data: array}> */
    private array $broadcasts = [];

    public function broadcastInitialized(UploadSession $session, string $userId): int
    {
        $this->broadcasts[] = [
            'type' => 'initialized',
            'session_id' => $session->sessionId->toString(),
            'user_id' => $userId,
            'data' => [
                'file_name' => $session->fileName,
                'total_size' => $session->totalSize->toBytes(),
                'total_chunks' => $session->totalChunks,
            ],
        ];

        return 1; // Simulated client count
    }

    public function broadcastChunkUploaded(UploadSession $session, string $userId): int
    {
        $this->broadcasts[] = [
            'type' => 'chunk_uploaded',
            'session_id' => $session->sessionId->toString(),
            'user_id' => $userId,
            'data' => [
                'uploaded_chunks' => count($session->getUploadedChunks()),
                'total_chunks' => $session->totalChunks,
                'progress' => $session->getProgress(),
            ],
        ];

        return 1;
    }

    public function broadcastCompleted(UploadSession $session, string $userId): int
    {
        $this->broadcasts[] = [
            'type' => 'completed',
            'session_id' => $session->sessionId->toString(),
            'user_id' => $userId,
            'data' => [
                'file_name' => $session->fileName,
                'completed_at' => $session->completedAt?->format('Y-m-d H:i:s'),
            ],
        ];

        return 1;
    }

    public function broadcastAborted(UploadSessionId $sessionId, string $userId, string $reason = 'User cancelled'): int
    {
        $this->broadcasts[] = [
            'type' => 'aborted',
            'session_id' => $sessionId->toString(),
            'user_id' => $userId,
            'data' => [
                'reason' => $reason,
            ],
        ];

        return 1;
    }

    public function broadcastError(UploadSessionId $sessionId, string $userId, string $error): int
    {
        $this->broadcasts[] = [
            'type' => 'error',
            'session_id' => $sessionId->toString(),
            'user_id' => $userId,
            'data' => [
                'error' => $error,
            ],
        ];

        return 1;
    }

    public function broadcastQuarantineStatus(UploadSession $session, string $userId): int
    {
        $this->broadcasts[] = [
            'type' => 'quarantine_status',
            'session_id' => $session->sessionId->toString(),
            'user_id' => $userId,
            'data' => [
                'quarantine_status' => $session->quarantineStatus->value,
            ],
        ];

        return 1;
    }

    public function getProgress(UploadSessionId $sessionId): ?array
    {
        // In-memory mock doesn't track progress state
        // Return null to indicate not available
        return null;
    }

    /**
     * Get all broadcast events (for testing)
     *
     * @return array<array{type: string, session_id: string, user_id: string, data: array}>
     */
    public function getBroadcasts(): array
    {
        return $this->broadcasts;
    }

    /**
     * Get broadcasts by type (for testing)
     *
     * @return array<array{type: string, session_id: string, user_id: string, data: array}>
     */
    public function getBroadcastsByType(string $type): array
    {
        return array_filter($this->broadcasts, fn($b) => $b['type'] === $type);
    }

    /**
     * Get broadcast count by type (for testing)
     */
    public function getBroadcastCount(string $type): int
    {
        return count($this->getBroadcastsByType($type));
    }

    /**
     * Clear all broadcasts (for testing)
     */
    public function clear(): void
    {
        $this->broadcasts = [];
    }
}
