"""
Unit Tests for Intent Scheduler

Tests the priority queue-based intent scheduler.
"""

import pytest
import time
from altrus.core.intent.scheduler import IntentScheduler, ScheduledIntent
from altrus.core.intent.intent import Intent, IntentPriority


class TestIntentScheduler:
    """Test suite for IntentScheduler"""

    def test_initialization(self):
        """Test scheduler initialization"""
        scheduler = IntentScheduler(max_concurrent=2)
        assert scheduler._max_concurrent == 2
        assert scheduler._executing_count == 0

    def test_enqueue_single_intent(self):
        """Test enqueueing a single intent"""
        scheduler = IntentScheduler()
        intent = Intent("test", "test_task", "test.capability", IntentPriority.NORMAL)

        scheduler.enqueue(intent)

        metrics = scheduler.get_metrics()
        assert metrics["queue_depth"] == 1

    def test_priority_ordering(self):
        """Test that higher priority intents are dequeued first"""
        scheduler = IntentScheduler(max_concurrent=10)

        low_intent = Intent("low", "low_task", "test.cap", IntentPriority.LOW)
        critical_intent = Intent("critical", "critical_task", "test.cap", IntentPriority.CRITICAL)
        normal_intent = Intent("normal", "normal_task", "test.cap", IntentPriority.NORMAL)
        high_intent = Intent("high", "high_task", "test.cap", IntentPriority.HIGH)

        scheduler.enqueue(low_intent)
        scheduler.enqueue(critical_intent)
        scheduler.enqueue(normal_intent)
        scheduler.enqueue(high_intent)

        # Dequeue should return in priority order
        first = scheduler.dequeue()
        assert first.intent_id == "critical"

        second = scheduler.dequeue()
        assert second.intent_id == "high"

        third = scheduler.dequeue()
        assert third.intent_id == "normal"

        fourth = scheduler.dequeue()
        assert fourth.intent_id == "low"

    def test_concurrent_limit(self):
        """Test that concurrent execution limit is enforced"""
        scheduler = IntentScheduler(max_concurrent=2)

        intent1 = Intent("intent1", "task1", "test.cap", IntentPriority.NORMAL)
        intent2 = Intent("intent2", "task2", "test.cap", IntentPriority.NORMAL)
        intent3 = Intent("intent3", "task3", "test.cap", IntentPriority.NORMAL)

        scheduler.enqueue(intent1)
        scheduler.enqueue(intent2)
        scheduler.enqueue(intent3)

        # Should dequeue first two
        first = scheduler.dequeue()
        assert first is not None

        second = scheduler.dequeue()
        assert second is not None

        # Third should be blocked by concurrent limit
        third = scheduler.dequeue()
        assert third is None

        # Mark one complete
        scheduler.mark_complete()

        # Now third should be available
        third = scheduler.dequeue()
        assert third is not None
        assert third.intent_id == "intent3"

    def test_fifo_within_priority(self):
        """Test FIFO ordering within same priority level"""
        scheduler = IntentScheduler(max_concurrent=10)

        intent1 = Intent("first", "task1", "test.cap", IntentPriority.NORMAL)
        time.sleep(0.01)  # Ensure different timestamps
        scheduler.enqueue(intent1)
        intent2 = Intent("second", "task2", "test.cap", IntentPriority.NORMAL)
        time.sleep(0.01)
        scheduler.enqueue(intent2)
        intent3 = Intent("third", "task3", "test.cap", IntentPriority.NORMAL)
        scheduler.enqueue(intent3)

        # Should dequeue in FIFO order
        first = scheduler.dequeue()
        assert first.intent_id == "first"

        second = scheduler.dequeue()
        assert second.intent_id == "second"

        third = scheduler.dequeue()
        assert third.intent_id == "third"

    def test_peek(self):
        """Test peeking at next intent without dequeueing"""
        scheduler = IntentScheduler()
        intent = Intent("test", "peek_task", "test.cap", IntentPriority.HIGH)

        scheduler.enqueue(intent)

        peeked = scheduler.peek()
        assert peeked is not None
        assert peeked.intent_id == "test"

        # Queue should still have the intent
        metrics = scheduler.get_metrics()
        assert metrics["queue_depth"] == 1

    def test_metrics(self):
        """Test scheduler metrics"""
        scheduler = IntentScheduler(max_concurrent=3)

        intent1 = Intent("i1", "high_task", "test.cap", IntentPriority.HIGH)
        intent2 = Intent("i2", "normal_task", "test.cap", IntentPriority.NORMAL)

        scheduler.enqueue(intent1)
        scheduler.enqueue(intent2)

        scheduled1 = scheduler.dequeue()
        assert scheduled1.intent_id == "i1"

        metrics = scheduler.get_metrics()
        assert metrics["queue_depth"] == 1
        assert metrics["executing_count"] == 1
        assert metrics["max_concurrent"] == 3
        assert metrics["total_queued"] == 2
        assert metrics["total_dequeued"] == 1


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
