import os
import tempfile
import threading
import unittest
from unittest.mock import Mock, patch

from olc.bean.olc_control_request import OlcControlRequest
from olc.config.properties_loader import OlcConfigManager
from olc.control.context.context import OlcContext
from olc.rule.olc_rule_convert import OlcRuleConvert
from olc.task_schedule.task_schedule import OlcScheduleManager


class TestOLC(unittest.TestCase):
    """OLC入口类测试"""

    def setUp(self):
        OlcConfigManager._instance = None
        OlcScheduleManager._instance = None
        OlcRuleConvert._instance = None
        self._reset_olc_class()

    def tearDown(self):
        self._reset_olc_class()
        OlcConfigManager._instance = None
        OlcScheduleManager._instance = None
        OlcRuleConvert._instance = None

    def _reset_olc_class(self):
        from olc.olc import OLC
        OLC._instance = None
        OLC._initialized = False

    def _create_temp_config(self, switch: bool = True):
        temp_dir = tempfile.mkdtemp()
        config_file = os.path.join(temp_dir, 'test-config.properties')
        with open(config_file, 'w') as f:
            f.write(f'olc.sdk.switch={str(switch).lower()}\n')
        return temp_dir, config_file

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_singleton_pattern(self, mock_rule, mock_schedule, mock_config):
        """测试OLC单例模式"""
        mock_sdk_config = Mock()
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance
        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        instance1 = OLC.get_instance()
        instance2 = OLC.get_instance()

        self.assertIs(instance1, instance2)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_with_switch_enabled(self, mock_rule, mock_schedule, mock_config):
        """测试开关开启时的process方法"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest(tags={"user": "test"}, token_number=10)
        context = olc.process(request)

        self.assertIsInstance(context, OlcContext)
        self.assertEqual(context.request, request)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_with_switch_disabled(self, mock_rule, mock_schedule, mock_config):
        """测试开关关闭时的process方法"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = False
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest(tags={"user": "test"}, token_number=10)
        context = olc.process(request)

        self.assertIsInstance(context, OlcContext)
        self.assertEqual(context.request, request)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_with_groups(self, mock_rule, mock_schedule, mock_config):
        """测试带groups参数的process方法"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest(tags={"user": "test"}, token_number=10)
        context = olc.process(request)

        self.assertIsInstance(context, OlcContext)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_clean_with_switch_enabled(self, mock_rule, mock_schedule, mock_config):
        """测试开关开启时的clean方法"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest()
        context = OlcContext(request)

        olc.clean(context)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_clean_with_switch_disabled(self, mock_rule, mock_schedule, mock_config):
        """测试开关关闭时的clean方法"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = False
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest()
        context = OlcContext(request)

        olc.clean(context)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_clean_with_none_context(self, mock_rule, mock_schedule, mock_config):
        """测试clean方法传入None参数"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        olc.clean(None)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_exception_handling(self, mock_rule, mock_schedule, mock_config):
        """测试process方法异常处理"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC
        from olc.control.handler_chain.box_handler_chain_builder import OlcHandlerChain

        original_chain = OlcHandlerChain.chain

        try:
            mock_chain = Mock()
            mock_chain.in_coming.side_effect = Exception("Chain error")
            OlcHandlerChain.chain = mock_chain

            olc = OLC.get_instance()

            request = OlcControlRequest()
            context = olc.process(request)

            self.assertIsInstance(context, OlcContext)
        finally:
            OlcHandlerChain.chain = original_chain

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_clean_exception_handling(self, mock_rule, mock_schedule, mock_config):
        """测试clean方法异常处理"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC
        from olc.control.handler_chain.box_handler_chain_builder import OlcHandlerChain

        original_chain = OlcHandlerChain.chain

        try:
            mock_chain = Mock()
            mock_chain.out_coming.side_effect = Exception("Chain error")
            OlcHandlerChain.chain = mock_chain

            olc = OLC.get_instance()

            request = OlcControlRequest()
            context = OlcContext(request)

            olc.clean(context)
        finally:
            OlcHandlerChain.chain = original_chain

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_graceful_shutdown(self, mock_rule, mock_schedule, mock_config):
        """测试优雅关闭"""
        mock_sdk_config = Mock()
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance
        mock_schedule_instance = Mock()
        mock_schedule.return_value = mock_schedule_instance
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()
        olc._graceful_shutdown()

        mock_schedule_instance.close.assert_called_once()

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_graceful_shutdown_with_exception(self, mock_rule, mock_schedule, mock_config):
        """测试优雅关闭异常处理"""
        mock_sdk_config = Mock()
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance
        mock_schedule_instance = Mock()
        mock_schedule_instance.close.side_effect = Exception("Close error")
        mock_schedule.return_value = mock_schedule_instance
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()
        olc._graceful_shutdown()

        mock_schedule_instance.close.assert_called_once()

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_signal_handler(self, mock_rule, mock_schedule, mock_config):
        """测试信号处理器"""
        mock_sdk_config = Mock()
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance
        mock_schedule_instance = Mock()
        mock_schedule.return_value = mock_schedule_instance
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()
        olc._signal_handler(2, None)

        mock_schedule_instance.close.assert_called_once()

    def test_thread_safety(self):
        """测试多线程安全性"""
        from olc.olc import OLC

        with patch('olc.olc.OlcConfigManager.get_instance') as mock_config, \
             patch('olc.olc.OlcScheduleManager.get_instance') as mock_schedule, \
             patch('olc.olc.OlcRuleConvert.get_instance') as mock_rule:

            mock_sdk_config = Mock()
            mock_sdk_config.collector_active = ""
            mock_config_instance = Mock()
            mock_config_instance.get_sdk_config.return_value = mock_sdk_config
            mock_config.return_value = mock_config_instance
            mock_schedule.return_value = Mock()
            mock_rule_instance = Mock()
            mock_rule.return_value = mock_rule_instance

            instances = []
            errors = []
            lock = threading.Lock()

            def get_olc_instance():
                try:
                    instance = OLC.get_instance()
                    with lock:
                        instances.append(instance)
                except Exception as e:
                    with lock:
                        errors.append(e)

            threads = [threading.Thread(target=get_olc_instance) for _ in range(10)]
            for t in threads:
                t.start()
            for t in threads:
                t.join()

            self.assertEqual(len(errors), 0, f"Errors occurred: {errors}")
            self.assertEqual(len(set(id(i) for i in instances)), 1, "Multiple instances created")

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_with_empty_tags(self, mock_rule, mock_schedule, mock_config):
        """测试空tags请求"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest(tags={}, token_number=0)
        context = olc.process(request)

        self.assertIsInstance(context, OlcContext)
        self.assertEqual(context.request.tags, {})

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_with_large_token_number(self, mock_rule, mock_schedule, mock_config):
        """测试大token_number边界条件"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest(tags={"user": "test"}, token_number=1000000)
        context = olc.process(request)

        self.assertIsInstance(context, OlcContext)
        self.assertEqual(context.request.token_number, 1000000)

    @patch('olc.olc.OlcConfigManager.get_instance')
    @patch('olc.olc.OlcScheduleManager.get_instance')
    @patch('olc.olc.OlcRuleConvert.get_instance')
    def test_process_with_negative_token_number(self, mock_rule, mock_schedule, mock_config):
        """测试负数token_number边界条件"""
        mock_sdk_config = Mock()
        mock_sdk_config.switch = True
        mock_sdk_config.collector_active = ""
        mock_config_instance = Mock()
        mock_config_instance.get_sdk_config.return_value = mock_sdk_config
        mock_config.return_value = mock_config_instance

        mock_schedule.return_value = Mock()
        mock_rule_instance = Mock()
        mock_rule.return_value = mock_rule_instance

        from olc.olc import OLC

        olc = OLC.get_instance()

        request = OlcControlRequest(tags={"user": "test"}, token_number=-100)
        context = olc.process(request)

        self.assertIsInstance(context, OlcContext)
        self.assertEqual(context.request.token_number, -100)


if __name__ == '__main__':
    unittest.main(verbosity=2)