import os
import json
import yaml
import configparser
import pytest
from pathlib import Path
from joy_config.loader import auto_loader


def test_auto_loader():
    # Test that the auto_loader function can load a module
    try:
        module = auto_loader()
        assert module is not None
    except FileNotFoundError:
        # This is acceptable if no default config files exist
        pass


class TestConfigLoaders:
    @pytest.fixture(scope="class")
    def setup_test_files(self, tmp_path_factory):
        base_dir = tmp_path_factory.mktemp("config_tests")
        
        # 创建YAML配置文件
        yaml_config = {
            "database": {
                "host": "localhost",
                "port": 5432,
                "username": "admin",
                "password": "secret"
            },
            "app": {
                "name": "TestApp",
                "debug": True,
                "log_level": "INFO"
            }
        }
        yaml_path = base_dir / "config.yaml"
        with open(yaml_path, "w") as f:
            yaml.dump(yaml_config, f)
            
        # 创建环境特定的YAML配置文件
        yaml_env_config = yaml_config.copy()
        yaml_env_config["database"]["host"] = "prod-server"
        yaml_env_config["app"]["debug"] = False
        yaml_env_path = base_dir / "config.prod.yaml"  # Changed to match implementation
        with open(yaml_env_path, "w") as f:
            yaml.dump(yaml_env_config, f)
        
        # 创建带有env属性的YAML配置文件
        yaml_with_env_config = yaml_config.copy()
        yaml_with_env_config["env"] = "prod"  # Add env attribute
        yaml_with_env_path = base_dir / "config_with_env.yaml"
        with open(yaml_with_env_path, "w") as f:
            yaml.dump(yaml_with_env_config, f)
        
        # 创建JSON配置文件
        json_config = {
            "server": {
                "host": "127.0.0.1",
                "port": 8080,
                "workers": 4
            },
            "logging": {
                "level": "DEBUG",
                "file": "app.log"
            },
            "features": ["auth", "api", "export"]
        }
        json_path = base_dir / "config.json"
        with open(json_path, "w") as f:
            json.dump(json_config, f)
            
        # 创建环境特定的JSON配置文件
        json_env_config = json_config.copy()
        json_env_config["server"]["host"] = "0.0.0.0"
        json_env_config["server"]["workers"] = 8
        json_env_path = base_dir / "config.test.json"  # Changed to match implementation
        with open(json_env_path, "w") as f:
            json.dump(json_env_config, f)
            
        # 创建带有env属性的JSON配置文件
        json_with_env_config = json_config.copy()
        json_with_env_config["env"] = "test"  # Add env attribute
        json_with_env_path = base_dir / "config_with_env.json"
        with open(json_with_env_path, "w") as f:
            json.dump(json_with_env_config, f)
        
        # 创建INI配置文件
        ini_config = configparser.ConfigParser()
        ini_config["DEFAULT"] = {"env": "development"}  # Already has env attribute
        ini_config["database"] = {
            "host": "db.example.com",
            "port": "3306",
            "user": "dbuser",
            "password": "dbpass"
        }
        ini_config["api"] = {
            "url": "https://api.example.com",
            "key": "api_key_123",
            "timeout": "30"
        }
        ini_path = base_dir / "config.ini"
        with open(ini_path, "w") as f:
            ini_config.write(f)
            
        # 创建环境特定的INI配置文件
        ini_env_config = configparser.ConfigParser()
        ini_env_config["DEFAULT"] = {"env": "staging"}
        ini_env_config["database"] = {
            "host": "staging-db.example.com",
            "port": "3306",
            "user": "stage_user",
            "password": "stage_pass"
        }
        ini_env_config["api"] = {
            "url": "https://staging-api.example.com",
            "key": "stage_api_key",
            "timeout": "60"
        }
        ini_env_path = base_dir / "config.staging.ini"  # Changed to match implementation
        with open(ini_env_path, "w") as f:
            ini_env_config.write(f)
        
        # 创建ENV配置文件
        env_content = """
        DEBUG=true
        PORT=3000
        DB_HOST=localhost
        DB_USER=root
        DB_PASS=password
        ALLOWED_HOSTS=localhost,127.0.0.1
        """
        env_path = base_dir / ".env"
        with open(env_path, "w") as f:
            f.write(env_content.strip())
            
        # 创建环境特定的ENV配置文件
        env_dev_content = """
        DEBUG=true
        PORT=3001
        DB_HOST=dev-db
        DB_USER=dev_user
        DB_PASS=dev_password
        ALLOWED_HOSTS=localhost,127.0.0.1,dev.example.com
        ENV=dev
        """
        env_dev_path = base_dir / ".env.dev"  # Changed to match implementation
        with open(env_dev_path, "w") as f:
            f.write(env_dev_content.strip())
            
        return {
            "base_dir": base_dir,
            "yaml_path": yaml_path,
            "yaml_env_path": yaml_env_path,
            "yaml_with_env_path": yaml_with_env_path,
            "json_path": json_path,
            "json_env_path": json_env_path,
            "json_with_env_path": json_with_env_path,
            "ini_path": ini_path,
            "ini_env_path": ini_env_path,
            "env_path": env_path,
            "env_dev_path": env_dev_path
        }
    
    def test_yaml_config_loading(self, setup_test_files):
        """测试YAML配置文件加载"""
        yaml_path = setup_test_files["yaml_path"]
        config = auto_loader(config_path=str(yaml_path))
        
        # 验证配置是否正确加载
        assert config is not None
        assert config.database.host == "localhost"
        assert config.database.port == 5432
        assert config.app.name == "TestApp"
        assert config.app.debug is True
        
        # 测试字典访问方式
        assert config["database"]["username"] == "admin"
        assert config["app"]["log_level"] == "INFO"
        
        # 测试get方法
        assert config.get("database.password") == "secret"
        assert config.get("nonexistent", "default") == "default"
    
    def test_yaml_env_config_loading(self, setup_test_files):
        """测试环境特定的YAML配置文件加载（通过env属性）"""
        yaml_path = setup_test_files["yaml_with_env_path"]
        config = auto_loader(config_path=str(yaml_path))
        
        # 验证环境特定的配置是否覆盖了基础配置
        assert config is not None
        assert config.database.host == "prod-server"  # 从环境特定配置加载
        assert config.database.port == 5432  # 从基础配置继承
        assert config.app.debug is False  # 从环境特定配置加载
    
    def test_json_config_loading(self, setup_test_files):
        """测试JSON配置文件加载"""
        json_path = setup_test_files["json_path"]
        config = auto_loader(config_path=str(json_path))
        
        # 验证配置是否正确加载
        assert config is not None
        assert config.server.host == "127.0.0.1"
        assert config.server.port == 8080
        assert config.logging.level == "DEBUG"
        
        # 测试列表访问
        assert "auth" in config.features
        assert len(config.features) == 3
        
        # 测试字典访问方式
        assert config["server"]["workers"] == 4
    
    def test_json_env_config_loading(self, setup_test_files):
        """测试环境特定的JSON配置文件加载（通过env属性）"""
        json_path = setup_test_files["json_with_env_path"]
        config = auto_loader(config_path=str(json_path))
        
        # 验证环境特定的配置是否覆盖了基础配置
        assert config is not None
        assert config.server.host == "0.0.0.0"  # 从环境特定配置加载
        assert config.server.workers == 8  # 从环境特定配置加载
        assert config.logging.level == "DEBUG"  # 从基础配置继承
    
    def test_ini_config_loading(self, setup_test_files):
        """测试INI配置文件加载"""
        ini_path = setup_test_files["ini_path"]
        config = auto_loader(config_path=str(ini_path))
        
        # 验证配置是否正确加载
        assert config is not None
        assert config.database.host == "db.example.com"
        assert config.database.port == 3306
        assert config.api.url == "https://api.example.com"
        
        # 测试字典访问方式
        assert config["database"]["user"] == "dbuser"
        assert config["api"]["timeout"] == 30
        
        # 测试默认部分
        assert config.DEFAULT.env == "development"
        
        # 测试环境特定的配置是否通过env属性加载
        # 由于INI文件已经有env属性，应该自动加载环境特定配置
        assert hasattr(config, "DEFAULT")
        assert config.DEFAULT.env == "development"  # 这里应该是development，因为没有development环境配置文件
    
    def test_env_config_loading(self, setup_test_files):
        """测试ENV配置文件加载"""
        env_path = setup_test_files["env_path"]
        config = auto_loader(config_path=str(env_path))
        
        # 验证配置是否正确加载
        assert config is not None
        assert config.DEBUG == "true"
        assert config.PORT == "3000"
        assert config.DB_HOST == "localhost"
        
        # 测试字典访问方式
        assert config["DB_USER"] == "root"
        assert config["ALLOWED_HOSTS"] == "localhost,127.0.0.1"
    
    def test_auto_detection(self, setup_test_files, monkeypatch):
        """测试自动检测配置文件"""
        base_dir = setup_test_files["base_dir"]
        
        # 修改工作目录以模拟项目根目录
        monkeypatch.chdir(base_dir)
        
        # 测试自动检测配置文件
        config = auto_loader()
        assert config is not None
        
        # 由于自动检测的顺序，应该会先找到config.json文件
        assert hasattr(config, "server") or hasattr(config, "DEBUG")
    
    def test_config_as_dict(self, setup_test_files):
        """测试配置对象转换为字典"""
        yaml_path = setup_test_files["yaml_path"]
        config = auto_loader(config_path=str(yaml_path))
        
        # 测试as_dict方法
        config_dict = config.as_dict()
        assert isinstance(config_dict, dict)
        assert config_dict["database"]["host"] == "localhost"
        assert config_dict["app"]["name"] == "TestApp"
    
    def test_nested_config_access(self, setup_test_files):
        """测试嵌套配置访问"""
        yaml_path = setup_test_files["yaml_path"]
        config = auto_loader(config_path=str(yaml_path))
        
        # 测试通过get方法访问嵌套配置
        assert config.get("database.host") == "localhost"
        assert config.get("app.debug") is True
        assert config.get("nonexistent.key", "default") == "default"
        
        # 测试通过字典方式访问嵌套配置
        assert config["database"]["host"] == "localhost"
        assert config["app"]["debug"] is True
        
        # 测试通过属性访问嵌套配置
        assert config.database.host == "localhost"
        assert config.app.debug is True