import os
import json
import time
import tempfile
import threading
import unittest
from http.server import HTTPServer, BaseHTTPRequestHandler

from utils.cloud_config import (
    compute_config_hash,
    fetch_remote_config,
    save_local_cache,
    load_local_config,
    load_remote_or_cache,
)


class MockConfigHTTPHandler(BaseHTTPRequestHandler):
    config_payload = [{"identifier": "test_group", "enable": True}]
    status_code = 200

    def do_GET(self):
        self.send_response(self.status_code)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        response_data = json.dumps(self.config_payload).encode("utf-8")
        self.wfile.write(response_data)

    def log_message(self, format, *args):
        pass  # 禁用标准输出日志，保持测试输出简洁


class TestCloudConfig(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # 启动本地 Mock HTTP 服务器
        cls.server = HTTPServer(("127.0.0.1", 0), MockConfigHTTPHandler)
        cls.port = cls.server.server_address[1]
        cls.server_thread = threading.Thread(target=cls.server.serve_forever)
        cls.server_thread.daemon = True
        cls.server_thread.start()
        cls.url = f"http://127.0.0.1:{cls.port}/config.json"

    @classmethod
    def tearDownClass(cls):
        cls.server.shutdown()
        cls.server.server_close()

    def test_compute_config_hash(self):
        data1 = {"b": 2, "a": 1}
        data2 = {"a": 1, "b": 2}
        data3 = {"a": 1, "b": 3}
        self.assertEqual(compute_config_hash(data1), compute_config_hash(data2))
        self.assertNotEqual(compute_config_hash(data1), compute_config_hash(data3))

    def test_fetch_remote_config_success(self):
        MockConfigHTTPHandler.config_payload = [{"identifier": "group_a", "enable": True}]
        MockConfigHTTPHandler.status_code = 200

        data = fetch_remote_config(self.url)
        self.assertEqual(data, [{"identifier": "group_a", "enable": True}])

    def test_fetch_remote_config_http_error(self):
        MockConfigHTTPHandler.status_code = 500
        with self.assertRaises(RuntimeError):
            fetch_remote_config(self.url)

    def test_load_remote_or_cache_success_and_save(self):
        MockConfigHTTPHandler.config_payload = [{"identifier": "group_remote", "enable": True}]
        MockConfigHTTPHandler.status_code = 200

        with tempfile.TemporaryDirectory() as tmp_dir:
            cache_path = os.path.join(tmp_dir, "cache.json")
            data, hash_val, loaded_remote = load_remote_or_cache(
                remote_url=self.url,
                local_cache_path=cache_path
            )

            self.assertTrue(loaded_remote)
            self.assertEqual(data, [{"identifier": "group_remote", "enable": True}])
            self.assertTrue(os.path.exists(cache_path))

            # 验证本地缓存是否被写入
            cached_data = load_local_config(cache_path)
            self.assertEqual(cached_data, [{"identifier": "group_remote", "enable": True}])

    def test_load_remote_or_cache_fallback_to_local(self):
        MockConfigHTTPHandler.status_code = 500  # 模拟云端 API 失败

        with tempfile.TemporaryDirectory() as tmp_dir:
            cache_path = os.path.join(tmp_dir, "cache.json")
            # 预先存入本地缓存
            save_local_cache(cache_path, [{"identifier": "group_cached", "enable": True}])

            data, hash_val, loaded_remote = load_remote_or_cache(
                remote_url=self.url,
                local_cache_path=cache_path
            )

            self.assertFalse(loaded_remote)
            self.assertEqual(data, [{"identifier": "group_cached", "enable": True}])


if __name__ == "__main__":
    unittest.main()
