<?php

declare(strict_types=1);

require_once __DIR__ . '/../bootstrap.php';

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Queue\InMemoryQueue;
use App\Framework\Queue\ValueObjects\QueuePriority;
use App\Framework\Queue\Wrappers\EventQueue;

// Example Event Classes für Tests
class UserRegisteredEvent
{
    public function __construct(
        public string $userId,
        public string $email
    ) {
    }
}

class OrderCreatedEvent
{
    public function __construct(
        public string $orderId,
        public float $total
    ) {
    }
}

class DomainUserDeletedEvent
{
    public function __construct(
        public string $userId
    ) {
    }
}

class SystemMaintenanceEvent
{
    public function __construct(
        public string $message
    ) {
    }
}

class IntegrationWebhookEvent
{
    public function __construct(
        public string $url,
        public array $payload
    ) {
    }
}

class NotificationEmailEvent
{
    public function __construct(
        public string $recipient,
        public string $subject
    ) {
    }
}

class CriticalSecurityEvent
{
    public function __construct(
        public string $threat,
        public string $ip
    ) {
    }
}

echo "🧪 Testing EventQueue Implementation\n";
echo "=====================================\n\n";

// Test 1: Basic Event Queue Operations
echo "1️⃣  Testing Basic Event Operations...\n";

$queue = new InMemoryQueue();
$eventQueue = new EventQueue($queue);

$userEvent = new UserRegisteredEvent('user-123', 'test@example.com');
$orderEvent = new OrderCreatedEvent('order-456', 99.99);

$eventQueue->pushEvent($userEvent);
$eventQueue->pushEvent($orderEvent);

assert($eventQueue->size() === 2, "❌ Queue size should be 2");
assert(! $eventQueue->isEmpty(), "❌ Queue should not be empty");

$poppedEvent = $eventQueue->popEvent();
assert($poppedEvent instanceof UserRegisteredEvent, "❌ First event should be UserRegisteredEvent");
assert($poppedEvent->userId === 'user-123', "❌ User ID should match");

echo "✅ Basic event operations work correctly\n\n";

// Test 2: Event Priority Methods
echo "2️⃣  Testing Event Priority Methods...\n";

$eventQueue->clear();

$domainEvent = new DomainUserDeletedEvent('user-789');
$systemEvent = new SystemMaintenanceEvent('Scheduled maintenance');
$integrationEvent = new IntegrationWebhookEvent('https://api.example.com', ['data' => 'test']);
$notificationEvent = new NotificationEmailEvent('user@example.com', 'Welcome');
$criticalEvent = new CriticalSecurityEvent('Brute force attack', '192.168.1.1');

// Push verschiedene Event-Typen
$eventQueue->pushDomainEvent($domainEvent);
$eventQueue->pushSystemEvent($systemEvent);
$eventQueue->pushIntegrationEvent($integrationEvent);
$eventQueue->pushNotificationEvent($notificationEvent);
$eventQueue->pushCriticalEvent($criticalEvent);

assert($eventQueue->size() === 5, "❌ Queue should contain 5 events");

// Test Priority Handling durch Queue-Implementation
$eventWithMeta = $eventQueue->popEventWithMetadata();
assert($eventWithMeta !== null, "❌ Should have event with metadata");
assert($eventWithMeta->priority->value >= QueuePriority::critical()->value, "❌ Should prioritize higher priority events");

echo "✅ Event priority methods work correctly\n\n";

// Test 3: Delayed Events
echo "3️⃣  Testing Delayed Events...\n";

$eventQueue->clear();

$delayedEvent = new OrderCreatedEvent('delayed-order', 150.00);
$delay = Duration::fromMinutes(5);

$eventQueue->pushDelayedEvent($delayedEvent, $delay);

$payload = $eventQueue->popEventWithMetadata();
assert($payload !== null, "❌ Should have delayed event");
assert($payload->delay->equals($delay), "❌ Delay should match");
assert($payload->job instanceof OrderCreatedEvent, "❌ Should be OrderCreatedEvent");

echo "✅ Delayed events work correctly\n\n";

// Test 4: Batch Operations
echo "4️⃣  Testing Batch Operations...\n";

$eventQueue->clear();

$events = [
    new UserRegisteredEvent('user-1', 'user1@example.com'),
    new UserRegisteredEvent('user-2', 'user2@example.com'),
    new OrderCreatedEvent('order-1', 50.00),
    new OrderCreatedEvent('order-2', 75.00),
];

// Test batch push
$eventQueue->pushBatch($events, QueuePriority::high());
assert($eventQueue->size() === 4, "❌ Should have 4 events after batch push");

// Test batch pop
$poppedEvents = $eventQueue->popBatch(2);
assert(count($poppedEvents) === 2, "❌ Should pop 2 events");
assert($eventQueue->size() === 2, "❌ Should have 2 events remaining");

echo "✅ Batch operations work correctly\n\n";

// Test 5: Smart Batch (Auto-Priority)
echo "5️⃣  Testing Smart Batch (Auto-Priority)...\n";

$eventQueue->clear();

$smartEvents = [
    new DomainUserDeletedEvent('user-auto-1'),
    new SystemMaintenanceEvent('Auto maintenance'),
    new IntegrationWebhookEvent('https://auto.example.com', []),
    new NotificationEmailEvent('auto@example.com', 'Auto subject'),
    new CriticalSecurityEvent('Auto threat', '10.0.0.1'),
];

$eventQueue->pushSmartBatch($smartEvents);
assert($eventQueue->size() === 5, "❌ Should have 5 events after smart batch");

// Kritische Events sollten zuerst kommen
$firstEvent = $eventQueue->popEvent();
assert($firstEvent instanceof CriticalSecurityEvent, "❌ Critical event should be processed first");

echo "✅ Smart batch with auto-priority works correctly\n\n";

// Test 6: Event Statistics
echo "6️⃣  Testing Event Statistics...\n";

$eventQueue->clear();
$eventQueue->pushDomainEvent(new DomainUserDeletedEvent('stats-user'));
$eventQueue->pushSystemEvent(new SystemMaintenanceEvent('Stats maintenance'));

$stats = $eventQueue->getStats();
assert($stats['type'] === 'event', "❌ Stats should indicate event type");
assert($stats['size'] === 2, "❌ Stats should show correct size");
assert(! $stats['is_empty'], "❌ Stats should show queue is not empty");

echo "✅ Event statistics work correctly\n\n";

// Test 7: Peek Operations
echo "7️⃣  Testing Peek Operations...\n";

$eventQueue->clear();
$peekEvent = new UserRegisteredEvent('peek-user', 'peek@example.com');
$eventQueue->pushEvent($peekEvent);

$originalSize = $eventQueue->size();
$peekedEvent = $eventQueue->peekEvent();

assert($peekedEvent instanceof UserRegisteredEvent, "❌ Peeked event should be UserRegisteredEvent");
assert($peekedEvent->userId === 'peek-user', "❌ Peeked event should have correct data");
assert($eventQueue->size() === $originalSize, "❌ Queue size should not change after peek");

echo "✅ Peek operations work correctly\n\n";

// Test 8: Event Type Recognition
echo "8️⃣  Testing Event Type Recognition (Private Method through Smart Batch)...\n";

$eventQueue->clear();

// Test verschiedene Event-Naming-Patterns
$testEvents = [
    new DomainUserDeletedEvent('domain-test'),  // Should be treated as domain event
    new SystemMaintenanceEvent('system-test'),   // Should be treated as system event
    new IntegrationWebhookEvent('https://test.com', []), // Should be treated as integration event
    new NotificationEmailEvent('test@test.com', 'test'), // Should be treated as notification event
    new CriticalSecurityEvent('test-threat', '1.1.1.1'), // Should be treated as critical event
];

$eventQueue->pushSmartBatch($testEvents);

// Überprüfe dass Events richtig priorisiert wurden
$events = [];
while (! $eventQueue->isEmpty()) {
    $events[] = $eventQueue->popEvent();
}

// Critical sollte zuerst kommen, dann Domain, etc.
assert($events[0] instanceof CriticalSecurityEvent, "❌ Critical events should have highest priority");

echo "✅ Event type recognition works correctly\n\n";

// Test 9: Empty Queue Handling
echo "9️⃣  Testing Empty Queue Handling...\n";

$eventQueue->clear();
assert($eventQueue->isEmpty(), "❌ Queue should be empty after clear");
assert($eventQueue->size() === 0, "❌ Queue size should be 0");

$nullEvent = $eventQueue->popEvent();
assert($nullEvent === null, "❌ Popping from empty queue should return null");

$nullPeek = $eventQueue->peekEvent();
assert($nullPeek === null, "❌ Peeking empty queue should return null");

$emptyBatch = $eventQueue->popBatch(5);
assert(empty($emptyBatch), "❌ Batch pop from empty queue should return empty array");

echo "✅ Empty queue handling works correctly\n\n";

// Test 10: Event Metadata Integration
echo "🔟 Testing Event Metadata Integration...\n";

$eventQueue->clear();
$metaEvent = new UserRegisteredEvent('meta-user', 'meta@example.com');
$eventQueue->pushEvent($metaEvent);

$payload = $eventQueue->popEventWithMetadata();
assert($payload !== null, "❌ Should have payload");
assert($payload->metadata !== null, "❌ Should have metadata");
assert($payload->metadata->type === 'event', "❌ Metadata type should be 'event'");
assert($payload->metadata->hasTag('event'), "❌ Metadata should have 'event' tag");

echo "✅ Event metadata integration works correctly\n\n";

echo "🎉 ALL EVENT QUEUE TESTS PASSED!\n";
echo "✨ EventQueue wrapper is ready for production use!\n";
