#!/usr/bin/env python3
"""
测试 Client 的默认超时时间

验证 OperatorClient 的默认超时时间是否正确设置为 8 小时（28800 秒）
"""

import unittest
import sys
import os
from pathlib import Path
from unittest.mock import Mock, patch

# Add the parent directory to the path to import sandai
sys.path.insert(0, str(Path(__file__).parent.parent))

from sandai.operator_client import OperatorClient, create_client


class TestClientDefaultTimeout(unittest.TestCase):
    """测试客户端默认超时时间"""

    def setUp(self):
        """设置测试环境"""
        # 模拟 Celery 相关的导入
        with patch('sandai.operator_client.Celery'), \
             patch('sandai.operator.env.get_celery_config') as mock_get_config, \
             patch('sandai.operator.env.get_default_celery_config') as mock_default_config:
            
            # 模拟配置
            mock_config = Mock()
            mock_config.broker_url = "redis://localhost:6379/0"
            mock_config.result_backend = "redis://localhost:6379/0"
            
            mock_get_config.return_value = mock_config
            mock_default_config.return_value = mock_config
            
            # 创建不指定 timeout 的客户端
            self.client_default = OperatorClient(
                operator_name="test-operator",
                operator_version="v1"
                # 不指定 timeout，使用默认值
            )
            
            # 创建指定 timeout 的客户端
            self.client_custom = OperatorClient(
                operator_name="test-operator",
                operator_version="v1",
                timeout=600  # 10 分钟
            )

    def test_default_timeout_is_8_hours(self):
        """测试默认超时时间是 8 小时"""
        expected_timeout = 8 * 60 * 60  # 8 小时 = 28800 秒
        
        self.assertEqual(
            self.client_default.timeout, 
            expected_timeout,
            f"默认超时时间应该是 {expected_timeout} 秒（8小时），实际是 {self.client_default.timeout} 秒"
        )
        
        print(f"✅ 默认超时时间验证通过: {self.client_default.timeout} 秒 = {self.client_default.timeout / 3600} 小时")

    def test_custom_timeout_override(self):
        """测试自定义超时时间可以覆盖默认值"""
        expected_timeout = 600  # 10 分钟
        
        self.assertEqual(
            self.client_custom.timeout,
            expected_timeout,
            f"自定义超时时间应该是 {expected_timeout} 秒，实际是 {self.client_custom.timeout} 秒"
        )
        
        print(f"✅ 自定义超时时间验证通过: {self.client_custom.timeout} 秒 = {self.client_custom.timeout / 60} 分钟")

    def test_create_client_default_timeout(self):
        """测试 create_client 函数的默认超时时间"""
        with patch('sandai.operator_client.Celery'), \
             patch('sandai.operator.env.get_celery_config') as mock_get_config, \
             patch('sandai.operator.env.get_default_celery_config') as mock_default_config:
            
            # 模拟配置
            mock_config = Mock()
            mock_config.broker_url = "redis://localhost:6379/0"
            mock_config.result_backend = "redis://localhost:6379/0"
            
            mock_get_config.return_value = mock_config
            mock_default_config.return_value = mock_config
            
            # 使用 create_client 创建客户端
            client = create_client("test-operator", "v1")
            
            expected_timeout = 8 * 60 * 60  # 8 小时
            
            self.assertEqual(
                client.timeout,
                expected_timeout,
                f"create_client 创建的客户端默认超时时间应该是 {expected_timeout} 秒"
            )
            
            print(f"✅ create_client 默认超时时间验证通过: {client.timeout} 秒")

    def test_timeout_calculation(self):
        """测试超时时间计算的正确性"""
        # 验证 8 小时的计算
        hours = 8
        minutes_per_hour = 60
        seconds_per_minute = 60
        
        calculated_timeout = hours * minutes_per_hour * seconds_per_minute
        expected_timeout = 28800
        
        self.assertEqual(
            calculated_timeout,
            expected_timeout,
            f"8小时应该等于 {expected_timeout} 秒，计算结果是 {calculated_timeout} 秒"
        )
        
        # 验证客户端使用的是正确的值
        self.assertEqual(
            self.client_default.timeout,
            calculated_timeout,
            "客户端超时时间应该与计算结果一致"
        )
        
        print(f"✅ 超时时间计算验证通过:")
        print(f"   8 小时 = {hours} × {minutes_per_hour} × {seconds_per_minute} = {calculated_timeout} 秒")
        print(f"   客户端超时时间: {self.client_default.timeout} 秒")

    def test_timeout_in_different_units(self):
        """测试超时时间的不同单位表示"""
        timeout_seconds = self.client_default.timeout
        
        # 转换为不同单位
        timeout_minutes = timeout_seconds / 60
        timeout_hours = timeout_seconds / 3600
        timeout_days = timeout_seconds / 86400
        
        print(f"✅ 默认超时时间的不同单位表示:")
        print(f"   秒: {timeout_seconds}")
        print(f"   分钟: {timeout_minutes}")
        print(f"   小时: {timeout_hours}")
        print(f"   天: {timeout_days:.2f}")
        
        # 验证是否等于 8 小时
        self.assertEqual(timeout_hours, 8.0, "超时时间应该正好是 8 小时")
        self.assertEqual(timeout_minutes, 480.0, "超时时间应该正好是 480 分钟")

    def test_timeout_rationale(self):
        """测试超时时间设置的合理性"""
        timeout_hours = self.client_default.timeout / 3600
        
        print(f"✅ 8小时超时时间的合理性分析:")
        print(f"   设置值: {timeout_hours} 小时")
        print(f"   适用场景:")
        print(f"   - 大型视频处理任务")
        print(f"   - 机器学习模型训练")
        print(f"   - 大数据批处理")
        print(f"   - 复杂的图像/音频处理")
        print(f"   优势:")
        print(f"   - 避免无限等待的风险")
        print(f"   - 为长时间任务提供充足时间")
        print(f"   - 在 spot 实例环境中提供合理的容错时间")
        
        # 验证超时时间在合理范围内
        self.assertGreater(timeout_hours, 1, "超时时间应该大于 1 小时，适合长时间任务")
        self.assertLess(timeout_hours, 24, "超时时间应该小于 24 小时，避免过长等待")


def run_timeout_tests():
    """运行超时测试"""
    # 创建测试套件
    loader = unittest.TestLoader()
    suite = unittest.TestSuite()
    
    # 添加测试用例
    suite.addTests(loader.loadTestsFromTestCase(TestClientDefaultTimeout))
    
    # 运行测试
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)
    
    return result.wasSuccessful()


if __name__ == '__main__':
    print("🧪 测试 Client 默认超时时间")
    print("=" * 50)
    
    # 运行测试
    success = run_timeout_tests()
    
    if success:
        print("\n🎉 所有超时时间测试通过!")
        print("\n📋 总结:")
        print("   ✅ 默认超时时间: 28800 秒（8小时）")
        print("   ✅ 避免了无限等待的风险")
        print("   ✅ 为长时间任务提供充足时间")
        print("   ✅ 适合 spot 实例等不稳定环境")
        sys.exit(0)
    else:
        print("\n💥 超时时间测试失败!")
        sys.exit(1)