import os
import yaml
from typing import Any, Optional, Dict, List
from pathlib import Path
from sunhpc.logs import Logs

slog = Logs(name="Config", show_time=True)

class Config:
    """功能完整的配置管理器（支持动态创建属性）"""
    
    def __init__(self, config_path: Optional[str] = None, auto_load: bool = True):
        self._config_path = config_path
        self._data = {}
        self._initialized = False
        
        if config_path and auto_load and os.path.exists(config_path):
            self.load(config_path)
        else:
            # 初始化空配置
            self._initialized = True
    
    def load(self, path: str):
        """从 YAML 文件加载配置"""
        with open(path, 'r', encoding='utf-8') as f:
            self._data = yaml.safe_load(f)
        # 清空现有属性
        for attr in list(self.__dict__.keys()):
            if not attr.startswith('_'):
                delattr(self, attr)
        self._build_attributes()
        self._initialized = True
    
    def getConfFile(self):
        return self._config_path

    def _build_attributes(self):
        """构建属性访问"""
        self._build_from_dict(self._data)
    
    def _build_from_dict(self, data: dict, parent_obj=None):
        """递归构建属性"""
        if parent_obj is None:
            parent_obj = self
        
        for key, value in data.items():
            # 处理键名中的空格
            clean_key = key.replace(' ', '_')
            
            if isinstance(value, dict):
                # 创建子对象
                sub_obj = Config()
                sub_obj._build_from_dict(value)
                setattr(parent_obj, clean_key, sub_obj)
            elif isinstance(value, list):
                # 转换列表中的字典
                converted_list = []
                for item in value:
                    if isinstance(item, dict):
                        sub_obj = Config()
                        sub_obj._build_from_dict(item)
                        converted_list.append(sub_obj)
                    else:
                        converted_list.append(item)
                setattr(parent_obj, clean_key, converted_list)
            else:
                setattr(parent_obj, clean_key, value)
    
    def __setattr__(self, name: str, value: Any):
        """拦截属性设置，支持动态创建配置项"""
        # 允许设置私有属性和已初始化的内部属性
        if name.startswith('_') or name in ['_config_path', '_data', '_initialized']:
            super().__setattr__(name, value)
            return
        
        # 动态创建配置项
        if isinstance(value, dict):
            # 如果设置的是字典，转换为 Config 对象
            sub_obj = Config()
            sub_obj._build_from_dict(value)
            super().__setattr__(name, sub_obj)
        elif isinstance(value, list):
            # 处理列表
            converted_list = []
            for item in value:
                if isinstance(item, dict):
                    sub_obj = Config()
                    sub_obj._build_from_dict(item)
                    converted_list.append(sub_obj)
                else:
                    converted_list.append(item)
            super().__setattr__(name, converted_list)
        else:
            super().__setattr__(name, value)
        
        # 标记数据已修改
        self._initialized = True
    
    def __getattr__(self, name: str):
        """访问不存在的属性时返回 None 而不是报错"""
        # 如果属性不存在，返回 None（可选行为）
        return None
    
    def save(self, path: Optional[str] = None, config_dict: Optional[Dict] = None):
        """保存配置到文件"""
        save_path = path or self._config_path
        if not save_path:
            raise ValueError("未指定保存路径")

        data = self.to_dict()
        if config_dict:
            data = config_dict

        # 确保目录存在
        Path(save_path).parent.mkdir(parents=True, exist_ok=True)
        
        with open(save_path, 'w', encoding='utf-8') as f:
            yaml.dump(data, f, 
                indent=4, 
                sort_keys=False,
                allow_unicode=True,
                default_flow_style=False, 
                )
        
        print(f"配置已保存到: {save_path}")
    
    def to_dict(self) -> dict:
        """转换回字典"""
        result = {}
        for key, value in self.__dict__.items():
            # 跳过私有属性
            if key.startswith('_'):
                continue
            
            if isinstance(value, Config):
                result[key] = value.to_dict()
            elif isinstance(value, list):
                converted_list = []
                for item in value:
                    if isinstance(item, Config):
                        converted_list.append(item.to_dict())
                    else:
                        converted_list.append(item)
                result[key] = converted_list
            else:
                result[key] = value
        return result
    
    def create_section(self, section_name: str):
        """创建一个新的配置节"""
        if not hasattr(self, section_name):
            setattr(self, section_name, Config())
        return getattr(self, section_name)
    
    def set_nested(self, path: str, value: Any):
        """通过点号路径设置值，例如: set_nested('network.interface', 'eth0')"""
        parts = path.split('.')
        obj = self
        
        # 导航到父对象
        for part in parts[:-1]:
            if not hasattr(obj, part):
                setattr(obj, part, Config())
            obj = getattr(obj, part)
        
        # 设置最终值
        setattr(obj, parts[-1], value)
    
    def get_nested(self, path: str, default: Any = None) -> Any:
        """通过点号路径获取值"""
        parts = path.split('.')
        obj = self
        
        for part in parts:
            if not hasattr(obj, part):
                return default
            obj = getattr(obj, part)
        
        return obj
    
    def __repr__(self):
        return f"Config({self.to_dict()})"
    
    def print_tree(self, indent: int = 0):
        """打印配置树（调试用）"""
        for key, value in self.__dict__.items():
            if key.startswith('_'):
                continue
            print('  ' * indent + f"{key}:", end=' ')
            if isinstance(value, Config):
                print()
                value.print_tree(indent + 1)
            elif isinstance(value, list):
                print(f"[{len(value)} items]")
                for i, item in enumerate(value):
                    print('  ' * (indent + 1) + f"[{i}]:", end=' ')
                    if isinstance(item, Config):
                        print()
                        item.print_tree(indent + 2)
                    else:
                        print(item)
            else:
                print(value)


# ============= 使用示例 =============
def main():
    # 1. 创建新配置（不加载现有文件）
    config = Config()  # 空配置
    
    # 2. 直接设置属性（会自动创建）
    config.interface = 'eth1'
    config.network = '1.1.1.1'
    config.netmask = '255.255.255.0'
    config.gateway = '192.168.1.1'
    
    # 3. 创建嵌套配置
    config.dhcp = Config()
    config.dhcp.enabled = True
    config.dhcp.start = '192.168.1.100'
    config.dhcp.end = '192.168.1.200'
    
    # 4. 或者通过点号路径设置（更简洁）
    config.set_nested('warewulf.port', 9873)
    config.set_nested('warewulf.secure', False)
    config.set_nested('warewulf.autobuild_overlays', True)
    
    # 5. 创建列表配置
    config.dns_servers = ['8.8.8.8', '8.8.4.4']
    
    # 6. 创建复杂的列表字典结构
    config.mounts = [
        {'source': '/etc/resolv.conf', 'dest': '/etc/resolv.conf', 'readonly': True},
        {'source': '/etc/hosts', 'dest': '/etc/hosts', 'readonly': True}
    ]
    
    # 7. 使用 create_section 方法
    nfs_section = config.create_section('nfs')
    nfs_section.enabled = True
    nfs_section.export_paths = [
        {'path': '/home', 'options': 'rw,sync'},
        {'path': '/opt', 'options': 'ro,sync'}
    ]
    
    # 8. 直接访问和修改
    print("=" * 50)
    print("配置访问示例:")
    print(f"interface: {config.interface}")
    print(f"network: {config.network}")
    print(f"DHCP enabled: {config.dhcp.enabled}")
    print(f"Warewulf port: {config.warewulf.port}")
    print(f"DNS servers: {config.dns_servers}")
    
    # 9. 修改已存在的配置
    config.network = '2.2.2.0'
    config.dhcp.enabled = False
    config.warewulf.secure = True
    
    # 10. 添加更多配置
    config.api = Config()
    config.api.enabled = True
    config.api.allowed_subnets = ['10.0.0.0/8', '192.168.0.0/16']
    
    config.ssh = Config()
    config.ssh.key_types = ['ed25519', 'rsa', 'ecdsa']
    
    # 11. 保存配置
    config.save('config_initial.yaml')
    
    # 12. 重新加载配置
    print("\n" + "=" * 50)
    print("重新加载配置:")
    new_config = Config('config_initial.yaml')
    print(f"加载的 interface: {new_config.interface}")
    print(f"加载的 network: {new_config.network}")
    print(f"加载的 DHCP enabled: {new_config.dhcp.enabled}")
    print(f"加载的 Warewulf port: {new_config.warewulf.port}")
    
    # 13. 配置树形展示
    print("\n" + "=" * 50)
    print("配置树形结构:")
    new_config.print_tree()
    
    # 14. 使用 get_nested 安全访问
    print("\n" + "=" * 50)
    print("安全访问示例:")
    port = new_config.get_nested('warewulf.port', 9090)
    print(f"warewulf.port: {port}")
    not_exist = new_config.get_nested('nonexist.key', 'default_value')
    print(f"不存在的键: {not_exist}")


# ============= 批量初始化配置 =============
class ConfigInitializer:
    """配置初始化器，支持字典或关键字参数批量设置"""
    
    @staticmethod
    def from_dict(config_dict: dict) -> Config:
        """从字典创建配置"""
        config = Config()
        ConfigInitializer._dict_to_config(config, config_dict)
        return config
    
    @staticmethod
    def _dict_to_config(config_obj: Config, data: dict):
        """递归将字典转换为配置对象"""
        for key, value in data.items():
            if isinstance(value, dict):
                sub_obj = Config()
                ConfigInitializer._dict_to_config(sub_obj, value)
                setattr(config_obj, key, sub_obj)
            elif isinstance(value, list):
                converted_list = []
                for item in value:
                    if isinstance(item, dict):
                        sub_obj = Config()
                        ConfigInitializer._dict_to_config(sub_obj, item)
                        converted_list.append(sub_obj)
                    else:
                        converted_list.append(item)
                setattr(config_obj, key, converted_list)
            else:
                setattr(config_obj, key, value)
    
    @staticmethod
    def from_yaml_template(template_path: str) -> Config:
        """从 YAML 模板文件初始化配置"""
        with open(template_path, 'r', encoding='utf-8') as f:
            data = yaml.safe_load(f)
        return ConfigInitializer.from_dict(data)


# ============= 快速初始化示例 =============

def quick_init_example():
    """快速初始化示例"""
    
    # 方式1: 逐个设置（你要求的方式）
    config = Config()
    config.interface = 'eth1'
    config.network = '1.1.1.1'
    config.netmask = '255.255.255.0'
    config.gateway = '192.168.1.1'
    config.dhcp_enabled = True
    config.dhcp_start = '192.168.1.100'
    config.dhcp_end = '192.168.1.200'
    config.save('config_by_assign.yaml')
    print("方式1: 逐个赋值保存完成")
    
    # 方式2: 使用 set_nested 批量设置
    config2 = Config()
    settings = {
        'interface': 'eth0',
        'network': '10.0.0.0',
        'netmask': '255.0.0.0',
        'dhcp.enabled': True,
        'dhcp.range_start': '10.0.0.100',
        'dhcp.range_end': '10.0.0.200',
        'warewulf.port': 9873,
        'warewulf.secure': True
    }
    for path, value in settings.items():
        config2.set_nested(path, value)
    config2.save('config_by_set_nested.yaml')
    print("方式2: set_nested 批量设置完成")
    
    # 方式3: 从字典初始化
    config_dict = {
        'interface': 'eth2',
        'network': '172.16.0.0',
        'netmask': '255.255.240.0',
        'dhcp': {
            'enabled': True,
            'start': '172.16.0.100',
            'end': '172.16.0.200'
        },
        'warewulf': {
            'port': 9873,
            'secure': False
        }
    }
    config3 = ConfigInitializer.from_dict(config_dict)
    config3.save('config_from_dict.yaml')
    print("方式3: 从字典初始化完成")


if __name__ == '__main__':
    main()
    print("\n" + "=" * 50)
    quick_init_example()