<?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\EmailQueue;

// Example Email Classes für Tests
class WelcomeEmail
{
    public function __construct(
        public string $recipient,
        public string $userName
    ) {
    }
}

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

class MarketingNewsletterEmail
{
    public function __construct(
        public string $recipient,
        public string $campaignId
    ) {
    }
}

class SystemAdminAlertEmail
{
    public function __construct(
        public string $recipient,
        public string $alertMessage,
        public string $severity
    ) {
    }
}

class BulkPromotionEmail
{
    public function __construct(
        public string $recipient,
        public string $promoCode,
        public float $discount
    ) {
    }
}

class CriticalSecurityNotificationEmail
{
    public function __construct(
        public string $recipient,
        public string $securityIssue
    ) {
    }
}

class ReminderFollowUpEmail
{
    public function __construct(
        public string $recipient,
        public string $taskId
    ) {
    }
}

class InvoiceEmail
{
    public function __construct(
        public string $recipient,
        public string $invoiceNumber
    ) {
    }
}

echo "📧 Testing EmailQueue Implementation\n";
echo "====================================\n\n";

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

$queue = new InMemoryQueue();
$emailQueue = new EmailQueue($queue);

$welcomeEmail = new WelcomeEmail('user@example.com', 'John Doe');
$orderEmail = new TransactionalOrderConfirmationEmail('customer@example.com', 'order-123', 99.99);

$emailQueue->pushEmail($welcomeEmail);
$emailQueue->pushEmail($orderEmail);

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

$poppedEmail = $emailQueue->popEmail();
assert($poppedEmail instanceof WelcomeEmail || $poppedEmail instanceof TransactionalOrderConfirmationEmail, "❌ Should pop valid email");

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

// Test 2: Email Type Methods
echo "2️⃣  Testing Email Type Methods...\n";

$emailQueue->clear();

$transactionalEmail = new TransactionalOrderConfirmationEmail('trans@example.com', 'order-456', 150.00);
$marketingEmail = new MarketingNewsletterEmail('marketing@example.com', 'campaign-789');
$systemEmail = new SystemAdminAlertEmail('admin@example.com', 'High CPU usage detected', 'warning');
$bulkEmail = new BulkPromotionEmail('bulk@example.com', 'SAVE20', 20.0);
$criticalEmail = new CriticalSecurityNotificationEmail('security@example.com', 'Multiple failed login attempts');

// Push verschiedene Email-Typen
$emailQueue->pushTransactionalEmail($transactionalEmail);
$emailQueue->pushMarketingEmail($marketingEmail);
$emailQueue->pushSystemEmail($systemEmail);
$emailQueue->pushBulkEmail($bulkEmail);
$emailQueue->pushCriticalEmail($criticalEmail);

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

// Critical Email sollte höchste Priorität haben
$firstEmail = $emailQueue->popEmail();
$payload = $emailQueue->popEmailWithMetadata();
assert($payload !== null, "❌ Should have email with metadata");

echo "✅ Email type methods work correctly\n\n";

// Test 3: Scheduled Emails
echo "3️⃣  Testing Scheduled Emails...\n";

$emailQueue->clear();

$scheduledEmail = new WelcomeEmail('scheduled@example.com', 'Scheduled User');
$delay = Duration::fromHours(2);

$emailQueue->pushScheduledEmail($scheduledEmail, $delay);

$payload = $emailQueue->popEmailWithMetadata();
assert($payload !== null, "❌ Should have scheduled email");
assert($payload->delay->equals($delay), "❌ Delay should match");
assert($payload->job instanceof WelcomeEmail, "❌ Should be WelcomeEmail");

echo "✅ Scheduled emails work correctly\n\n";

// Test 4: Reminder Emails
echo "4️⃣  Testing Reminder Emails...\n";

$emailQueue->clear();

$reminderEmail = new ReminderFollowUpEmail('reminder@example.com', 'task-123');
$reminderDelay = Duration::fromDays(1);

$emailQueue->pushReminderEmail($reminderEmail, $reminderDelay);

$payload = $emailQueue->popEmailWithMetadata();
assert($payload !== null, "❌ Should have reminder email");
assert($payload->delay->equals($reminderDelay), "❌ Reminder delay should match");

echo "✅ Reminder emails work correctly\n\n";

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

$emailQueue->clear();

$emails = [
    new WelcomeEmail('batch1@example.com', 'User 1'),
    new WelcomeEmail('batch2@example.com', 'User 2'),
    new TransactionalOrderConfirmationEmail('batch3@example.com', 'order-batch', 75.00),
    new MarketingNewsletterEmail('batch4@example.com', 'batch-campaign'),
];

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

// Test batch pop
$poppedEmails = $emailQueue->popBatch(2);
assert(count($poppedEmails) === 2, "❌ Should pop 2 emails");
assert($emailQueue->size() === 2, "❌ Should have 2 emails remaining");

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

// Test 6: Smart Batch (Auto-Type-Detection)
echo "6️⃣  Testing Smart Batch (Auto-Type-Detection)...\n";

$emailQueue->clear();

$smartEmails = [
    new TransactionalOrderConfirmationEmail('auto@example.com', 'auto-order', 100.00),
    new MarketingNewsletterEmail('auto-marketing@example.com', 'auto-campaign'),
    new SystemAdminAlertEmail('auto-admin@example.com', 'Auto alert', 'info'),
    new BulkPromotionEmail('auto-bulk@example.com', 'AUTO10', 10.0),
    new CriticalSecurityNotificationEmail('auto-critical@example.com', 'Auto security issue'),
    new InvoiceEmail('auto-invoice@example.com', 'INV-001'),
];

$emailQueue->pushSmartBatch($smartEmails);
assert($emailQueue->size() === 6, "❌ Should have 6 emails after smart batch");

// Critical sollte zuerst kommen
$firstEmail = $emailQueue->popEmail();
assert($firstEmail instanceof CriticalSecurityNotificationEmail, "❌ Critical email should be processed first");

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

// Test 7: Email Statistics
echo "7️⃣  Testing Email Statistics...\n";

$emailQueue->clear();
$emailQueue->pushTransactionalEmail(new TransactionalOrderConfirmationEmail('stats@example.com', 'stats-order', 50.00));
$emailQueue->pushMarketingEmail(new MarketingNewsletterEmail('stats-marketing@example.com', 'stats-campaign'));

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

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

// Test 8: Scheduled Email Detection
echo "8️⃣  Testing Scheduled Email Detection...\n";

$emailQueue->clear();

// Add immediate emails
$emailQueue->pushTransactionalEmail(new TransactionalOrderConfirmationEmail('immediate@example.com', 'immediate-order', 25.00));

// Add scheduled emails
$emailQueue->pushScheduledEmail(new WelcomeEmail('scheduled1@example.com', 'User 1'), Duration::fromHours(1));
$emailQueue->pushScheduledEmail(new WelcomeEmail('scheduled2@example.com', 'User 2'), Duration::fromHours(2));

$scheduledEmails = $emailQueue->getScheduledEmails();
assert(count($scheduledEmails) === 2, "❌ Should detect 2 scheduled emails");

$statusCounts = $emailQueue->getDeliveryStatusCounts();
assert($statusCounts['pending'] === 3, "❌ Should have 3 pending emails");
assert($statusCounts['scheduled'] === 2, "❌ Should have 2 scheduled emails");
assert($statusCounts['immediate'] === 1, "❌ Should have 1 immediate email");

echo "✅ Scheduled email detection works correctly\n\n";

// Test 9: Rate-Limited Bulk Processing
echo "9️⃣  Testing Rate-Limited Bulk Processing...\n";

$emailQueue->clear();

$bulkEmails = [
    new BulkPromotionEmail('bulk1@example.com', 'BULK1', 5.0),
    new BulkPromotionEmail('bulk2@example.com', 'BULK2', 10.0),
    new BulkPromotionEmail('bulk3@example.com', 'BULK3', 15.0),
];

$interval = Duration::fromMinutes(5);
$emailQueue->pushBulkWithRateLimit($bulkEmails, $interval);

assert($emailQueue->size() === 3, "❌ Should have 3 bulk emails");

// Check that delays are applied correctly by collecting all payloads
$payloads = [];
while (! $emailQueue->isEmpty()) {
    $payload = $emailQueue->popEmailWithMetadata();
    if ($payload !== null) {
        $payloads[] = $payload;
    }
}

assert(count($payloads) === 3, "❌ Should have 3 payloads");

// Sort payloads by delay to verify rate limiting
usort($payloads, fn ($a, $b) => $a->delay->toSeconds() <=> $b->delay->toSeconds());

assert($payloads[0]->delay->toSeconds() === 0.0, "❌ First email should have no delay");
assert($payloads[1]->delay->toSeconds() === 300.0, "❌ Second email should have 5-minute delay");
assert($payloads[2]->delay->toSeconds() === 600.0, "❌ Third email should have 10-minute delay");

echo "✅ Rate-limited bulk processing works correctly\n\n";

// Test 10: Email Type Filtering
echo "🔟 Testing Email Type Filtering...\n";

$emailQueue->clear();

$emailQueue->pushTransactionalEmail(new TransactionalOrderConfirmationEmail('filter1@example.com', 'filter-order-1', 30.00));
$emailQueue->pushTransactionalEmail(new TransactionalOrderConfirmationEmail('filter2@example.com', 'filter-order-2', 40.00));
$emailQueue->pushMarketingEmail(new MarketingNewsletterEmail('filter-marketing@example.com', 'filter-campaign'));

$transactionalEmails = $emailQueue->getEmailsByType(TransactionalOrderConfirmationEmail::class);
assert(count($transactionalEmails) === 2, "❌ Should find 2 transactional emails");

// Queue should still have the marketing email
assert($emailQueue->size() === 1, "❌ Should have 1 email remaining (marketing)");

echo "✅ Email type filtering works correctly\n\n";

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

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

$nullEmail = $emailQueue->popEmail();
assert($nullEmail === null, "❌ Popping from empty queue should return null");

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

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

$emptyScheduled = $emailQueue->getScheduledEmails();
assert(empty($emptyScheduled), "❌ Scheduled emails from empty queue should return empty array");

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

// Test 12: Email Metadata Integration
echo "1️⃣2️⃣ Testing Email Metadata Integration...\n";

$emailQueue->clear();
$metaEmail = new WelcomeEmail('meta@example.com', 'Meta User');
$emailQueue->pushEmail($metaEmail);

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

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

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