"""
配置解析器

负责解析引擎配置（YAML）并提取启用的工具及其配置。

架构说明：
- 命令模板：在 command_templates.py 中定义（基础命令 + 可选参数映射）
- 工具配置：从引擎配置（engine_config YAML 字符串）读取
- 无默认配置文件：所有配置必须在引擎配置中提供

核心函数：
- parse_enabled_tools_from_dict(): 解析并过滤启用的工具，返回工具配置字典

返回格式：
- {'subfinder': {'enabled': True, 'threads': 10, 'timeout': 600}}
- timeout 是必需参数，支持整数或 'auto'（由具体 Flow 处理）
"""

import logging
from typing import Dict, Any

logger = logging.getLogger(__name__)


def _normalize_config_keys(config: Dict[str, Any]) -> Dict[str, Any]:
    """
    将配置字典的 key 中划线转换为下划线
    
    规范约定：
    - 配置文件统一用中划线（贴近 CLI 参数风格）
    - 代码里统一用下划线（Python 标识符规范）
    - 此处自动转换：rate-limit → rate_limit
    
    Args:
        config: 原始配置字典
        
    Returns:
        key 已转换的新字典
        
    Raises:
        ValueError: 配置为 None 或非字典类型时抛出
    """
    if config is None:
        raise ValueError("配置不能为空（None），请检查 YAML 格式，确保冒号后有配置内容或使用 {} 表示空配置")
    if not isinstance(config, dict):
        raise ValueError(f"配置格式错误：期望 dict，实际 {type(config).__name__}")
    return {
        k.replace('-', '_') if isinstance(k, str) else k: v
        for k, v in config.items()
    }


def _parse_subdomain_discovery_config(scan_config: Dict[str, Any]) -> Dict[str, Any]:
    """
    解析子域名发现配置（4阶段流程）
    
    配置格式：
        {
            'passive_tools': {'subfinder': {...}, ...},
            'bruteforce': {'enabled': True, 'subdomain_bruteforce': {...}},
            'permutation': {'enabled': True, 'subdomain_permutation_resolve': {...}},
            'resolve': {'enabled': True, 'subdomain_resolve': {...}}
        }
    
    Args:
        scan_config: subdomain_discovery 的配置字典
    
    Returns:
        配置字典，供 Flow 使用
    """
    if 'passive_tools' not in scan_config:
        logger.warning("子域名发现配置缺少 passive_tools")
        return {}
    
    result = {}
    
    # Stage 1: 被动收集工具
    passive_tools = scan_config.get('passive_tools', {})
    enabled_passive = {}
    for name, config in passive_tools.items():
        if isinstance(config, dict) and config.get('enabled', False):
            enabled_passive[name] = _normalize_config_keys(config)
    result['passive_tools'] = enabled_passive
    
    # Stage 2: 字典爆破（可选）
    bruteforce = scan_config.get('bruteforce', {})
    if bruteforce.get('enabled', False):
        # 转换内部工具配置的 key
        normalized_bruteforce = _normalize_config_keys(bruteforce)
        if 'subdomain_bruteforce' in normalized_bruteforce:
            normalized_bruteforce['subdomain_bruteforce'] = _normalize_config_keys(
                normalized_bruteforce['subdomain_bruteforce']
            )
        result['bruteforce'] = normalized_bruteforce
    
    # Stage 3: 变异生成（可选）
    permutation = scan_config.get('permutation', {})
    if permutation.get('enabled', False):
        normalized_permutation = _normalize_config_keys(permutation)
        if 'subdomain_permutation_resolve' in normalized_permutation:
            normalized_permutation['subdomain_permutation_resolve'] = _normalize_config_keys(
                normalized_permutation['subdomain_permutation_resolve']
            )
        result['permutation'] = normalized_permutation
    
    # Stage 4: 存活验证（可选）
    resolve = scan_config.get('resolve', {})
    if resolve.get('enabled', False):
        normalized_resolve = _normalize_config_keys(resolve)
        if 'subdomain_resolve' in normalized_resolve:
            normalized_resolve['subdomain_resolve'] = _normalize_config_keys(
                normalized_resolve['subdomain_resolve']
            )
        result['resolve'] = normalized_resolve
    
    logger.info(
        f"子域名发现: passive={len(enabled_passive)}, "
        f"bruteforce={'bruteforce' in result}, "
        f"permutation={'permutation' in result}, "
        f"resolve={'resolve' in result}"
    )
    return result


def parse_enabled_tools_from_dict(
    scan_type: str,
    parsed_config: Dict[str, Any]
) -> Dict[str, Dict[str, Any]]:
    """
    从解析后的配置字典中获取启用的工具及其配置
    
    Args:
        scan_type: 扫描类型 (subdomain_discovery, port_scan, site_scan, directory_scan)
        parsed_config: 已解析的配置字典
    
    Returns:
        启用的工具配置字典 {tool_name: tool_config}
        对于 subdomain_discovery，返回完整的配置结构（支持4阶段增强流程）
    
    Raises:
        ValueError: 配置格式错误或必需参数缺失/无效时抛出
    """
    if not parsed_config:
        logger.warning(f"配置字典为空 - scan_type: {scan_type}")
        return {}
    
    if scan_type not in parsed_config:
        logger.warning(f"配置中未找到扫描类型: {scan_type}")
        return {}
    
    scan_config = parsed_config[scan_type]
    
    # 子域名发现支持增强配置格式（4阶段）
    if scan_type == 'subdomain_discovery':
        return _parse_subdomain_discovery_config(scan_config)
    
    if 'tools' not in scan_config:
        logger.warning(f"扫描类型 {scan_type} 未配置任何工具")
        return {}
    
    tools = scan_config['tools']
    
    # 过滤出启用的工具
    enabled_tools = {}
    for name, config in tools.items():
        if not isinstance(config, dict):
            raise ValueError(f"工具 {name} 配置格式错误：期望 dict，实际 {type(config).__name__}")
        
        # 检查是否启用（默认为 False）
        enabled_value = config.get('enabled', False)
        
        # 验证 enabled 字段类型
        if not isinstance(enabled_value, bool):
            raise ValueError(
                f"工具 {name} 的 enabled 字段类型错误：期望 bool，实际 {type(enabled_value).__name__}"
            )
        
        if enabled_value:
            # timeout 默认为 'auto'，由具体 Flow 自动计算
            timeout_value = config.get('timeout', 'auto')
            
            # 验证 timeout 值的有效性
            if timeout_value != 'auto':
                if isinstance(timeout_value, int):
                    if timeout_value <= 0:
                        raise ValueError(f"工具 {name} 的 timeout 参数无效（{timeout_value}），必须大于0")
                else:
                    raise ValueError(
                        f"工具 {name} 的 timeout 参数类型错误：期望 int 或 'auto'，实际 {type(timeout_value).__name__}"
                    )
            
            # 将配置 key 中划线转为下划线，统一给下游代码使用
            normalized_config = _normalize_config_keys(config)
            normalized_config['timeout'] = timeout_value  # 确保 timeout 存在
            enabled_tools[name] = normalized_config
    
    logger.info(f"扫描类型: {scan_type}, 启用工具: {len(enabled_tools)}/{len(tools)}")
    
    return enabled_tools
