"""
调度器单元测试
"""
import pytest
from app.services.scheduler import (
    AgentScheduler,
    RoundRobinScheduler,
    WeightedRoundRobinScheduler,
    LeastConnectionsScheduler,
    LeastResponseTimeScheduler,
    CapabilityMatchScheduler,
)
from datetime import datetime, timedelta


class MockAgent:
    """模拟 Agent"""
    def __init__(self, id, status='online', weight=10, priority=5, 
                 current_sessions=0, connection_limit=5, capabilities=None,
                 last_heartbeat=None):
        self.id = id
        self.status = status
        self.weight = weight
        self.priority = priority
        self.current_sessions = current_sessions
        self.connection_limit = connection_limit
        self.capabilities = capabilities or []
        self.last_heartbeat = last_heartbeat


class TestRoundRobinScheduler:
    """轮询调度器测试"""
    
    def test_select_agent(self):
        """测试选择 Agent"""
        scheduler = RoundRobinScheduler()
        agents = [
            MockAgent(id='agent1'),
            MockAgent(id='agent2'),
            MockAgent(id='agent3'),
        ]
        
        # 轮询选择
        agent1 = scheduler.select_agent(agents)
        agent2 = scheduler.select_agent(agents)
        agent3 = scheduler.select_agent(agents)
        agent4 = scheduler.select_agent(agents)  # 循环回第一个
        
        assert agent1.id == 'agent1'
        assert agent2.id == 'agent2'
        assert agent3.id == 'agent3'
        assert agent4.id == 'agent1'
    
    def test_no_online_agents(self):
        """测试无在线 Agent"""
        scheduler = RoundRobinScheduler()
        agents = [
            MockAgent(id='agent1', status='offline'),
            MockAgent(id='agent2', status='offline'),
        ]
        
        agent = scheduler.select_agent(agents)
        assert agent is None


class TestWeightedRoundRobinScheduler:
    """加权轮询调度器测试"""
    
    def test_weight_distribution(self):
        """测试权重分布"""
        scheduler = WeightedRoundRobinScheduler()
        agents = [
            MockAgent(id='agent1', weight=3),
            MockAgent(id='agent2', weight=1),
        ]
        
        # 统计选择次数
        counts = {'agent1': 0, 'agent2': 0}
        for _ in range(100):
            agent = scheduler.select_agent(agents)
            counts[agent.id] += 1
        
        # agent1 权重 3，agent2 权重 1，比例应该约 3:1
        assert counts['agent1'] > counts['agent2']
    
    def test_zero_weight(self):
        """测试零权重"""
        scheduler = WeightedRoundRobinScheduler()
        agents = [
            MockAgent(id='agent1', weight=0),
            MockAgent(id='agent2', weight=0),
        ]
        
        # 权重都为 0 时返回第一个
        agent = scheduler.select_agent(agents)
        assert agent is not None


class TestLeastConnectionsScheduler:
    """最少连接调度器测试"""
    
    def test_select_least_connections(self):
        """测试选择最少连接"""
        scheduler = LeastConnectionsScheduler()
        agents = [
            MockAgent(id='agent1', current_sessions=5),
            MockAgent(id='agent2', current_sessions=2),
            MockAgent(id='agent3', current_sessions=8),
        ]
        
        agent = scheduler.select_agent(agents)
        assert agent.id == 'agent2'
    
    def test_all_at_limit(self):
        """测试所有 Agent 都达上限"""
        scheduler = LeastConnectionsScheduler()
        agents = [
            MockAgent(id='agent1', current_sessions=5, connection_limit=5),
            MockAgent(id='agent2', current_sessions=5, connection_limit=5),
        ]
        
        agent = scheduler.select_agent(agents)
        assert agent is None


class TestCapabilityMatchScheduler:
    """能力匹配调度器测试"""
    
    def test_match_capabilities(self):
        """测试能力匹配"""
        scheduler = CapabilityMatchScheduler()
        agents = [
            MockAgent(id='agent1', capabilities=['chat', 'code']),
            MockAgent(id='agent2', capabilities=['chat']),
            MockAgent(id='agent3', capabilities=['code', 'translate']),
        ]
        
        # 需要 code 能力
        agent = scheduler.select_agent(agents, {'capabilities': ['code']})
        assert agent.id in ['agent1', 'agent3']
    
    def test_no_matching_capabilities(self):
        """测试无匹配能力"""
        scheduler = CapabilityMatchScheduler()
        agents = [
            MockAgent(id='agent1', capabilities=['chat']),
        ]
        
        # 需要 code 能力但无 Agent 具备
        agent = scheduler.select_agent(agents, {'capabilities': ['code']})
        # 回退到加权轮询
        assert agent is not None


class TestAgentScheduler:
    """Agent 调度器工厂测试"""
    
    def test_available_strategies(self):
        """测试可用策略"""
        strategies = AgentScheduler.get_available_strategies()
        
        assert 'round_robin' in strategies
        assert 'weighted_round_robin' in strategies
        assert 'least_connections' in strategies
        assert 'least_response_time' in strategies
        assert 'capability_match' in strategies
    
    def test_default_strategy(self):
        """测试默认策略"""
        scheduler = AgentScheduler()
        assert scheduler.get_strategy() == 'weighted_round_robin'
    
    def test_custom_strategy(self):
        """测试自定义策略"""
        scheduler = AgentScheduler('round_robin')
        assert scheduler.get_strategy() == 'round_robin'
