# -*- coding: utf-8 -*-
"""Config file reading, merging, templating, and sys.config generation."""

from .shared import *
from .erlang import get_local_ip
from .project_config import get_project_config_path, get_server_manager_config_dir


def _first_existing_config(paths: Tuple[Path, ...]) -> Optional[Path]:
    return next((path for path in paths if path.exists()), None)

def read_merged_config(
    server_root: str,
    server_dir: str = None,
    run_dir: str = None,
) -> Dict[str, str]:
    """读取合并后的配置（优先级从低到高）
    
    优先级：default.config < config/project.config < user.config(项目根/.server_manager/config) < 运行目录下配置(run_dir) < kv.config
    
    Args:
        server_root: 服务器根目录
        server_dir: 服务器目录名（可选，如 ddxq_game_s1）。
                    若提供，则读取 运行目录/{server_dir}/config/kv.config 作为最高优先级。
        run_dir: 运行目录（可选）。若提供，则从运行目录下读取配置：
                 - run_dir/config/user.config 或 run_dir/user.config（兼容旧用户配置文件）
                 - run_dir/server_dir/config/kv.config（与 server_dir 同时提供时）
                 用于命令行等场景下“用运行目录的配置”获取 IP 等。
    
    Returns:
        合并后的配置字典
    """
    config_path = get_server_manager_config_dir(server_root)
    merged = {}

    # Priority, low to high: default.config < config/project.config < user.config.
    default_config_file = _first_existing_config((
        config_path / DEFAULT_CONFIG_FILE,
        config_path / LEGACY_DEFAULT_CONFIG_FILE,
    ))
    if default_config_file:
        merged.update(read_config_file(str(default_config_file)))

    project_config_file = get_project_config_path(server_root)
    if project_config_file.exists():
        merged.update(read_config_file(str(project_config_file)))

    user_config_file = _first_existing_config((
        config_path / USER_CONFIG_FILE,
        config_path / LEGACY_USER_CONFIG_FILE,
    ))
    if user_config_file:
        merged.update(read_config_file(str(user_config_file)))

    # Optional run-dir user config override for command-line/run-dir scenarios.
    if run_dir:
        run_path = Path(run_dir)
        for user_in_run in (
            run_path / 'config' / USER_CONFIG_FILE,
            run_path / USER_CONFIG_FILE,
            run_path / 'config' / LEGACY_USER_CONFIG_FILE,
            run_path / LEGACY_USER_CONFIG_FILE,
        ):
            if user_in_run.exists():
                merged.update(read_config_file(str(user_in_run)))
                break
    
    # 4. kv.config（最高优先级）：在运行目录或 server_root/run 下
    if server_dir:
        if run_dir:
            kv_config_file = Path(run_dir) / server_dir / 'config' / 'kv.config'
        else:
            kv_config_file = Path(server_root) / 'run' / server_dir / 'config' / 'kv.config'
        if kv_config_file.exists():
            merged.update(read_config_file(str(kv_config_file)))
    
    # 本机 IP：不再依赖配置文件中的 ip / game_host，统一使用当前机器地址
    local_ip = get_local_ip()
    merged['ip'] = local_ip
    merged['game_host'] = local_ip
    return merged


def read_config_file(file_path: str) -> Dict[str, str]:
    """读取配置文件（key=value 格式）
    
    Args:
        file_path: 配置文件路径
    
    Returns:
        配置字典
    """
    config = {}
    path = Path(file_path)
    if not path.exists():
        return config
    
    with open(path, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if '=' in line and not line.startswith('#') and not line.startswith('%'):
                key, value = line.split('=', 1)
                key = key.strip()
                value = value.strip()
                if not key:
                    continue
                # 去除引号
                value = re.sub(r'^"|"$', '', value)
                config[key] = value
    return config


def write_config_file(file_path: str, config: Dict[str, str]):
    """写入配置文件（key=value 格式）
    
    Args:
        file_path: 配置文件路径
        config: 配置字典
    """
    lines = [f"{key}={value}\n" for key, value in config.items()]
    with open(file_path, 'w', encoding='utf-8') as f:
        f.writelines(lines)


def replace_placeholders(template_content: str, config: Dict[str, str]) -> str:
    """替换模板中的占位符 ${key}
    
    Args:
        template_content: 模板内容
        config: 配置字典
    
    Returns:
        替换后的内容
    """
    result = template_content
    for key, value in config.items():
        result = result.replace(f'${{{key}}}', str(value))
    return result


def get_template_file(config_path: Path, server_type: str) -> Optional[Path]:
    """根据服务器类型获取对应的模板文件
    
    Args:
        config_path: 配置目录路径
        server_type: 服务器类型
    
    Returns:
        模板文件路径，如果不存在返回 None
    """
    # 服务器类型到模板文件的映射
    template_map = {
        'game_server': 'sys_game.config.example',
        'login_server': 'sys_login.config.example',
        'client_server': 'sys_client.config.example',
        'center_server': 'sys_center.config.example',
        'cross_server': 'sys_cross.config.example',
    }
    
    template_name = template_map.get(server_type, 'sys_game.config.example')
    template_file = config_path / template_name
    
    if template_file.exists():
        return template_file
    
    # 尝试不带 .example 的版本
    alt_template = config_path / template_name.replace('.example', '')
    if alt_template.exists():
        return alt_template
    
    return None


def build_replace_map(config: Dict[str, str]) -> Dict[str, str]:
    """构建占位符替换映射（直接使用 ${xxx} 格式）
    
    Args:
        config: 原始配置字典
    
    Returns:
        替换映射字典
    """
    replace_map = {}
    
    # 移除引号的辅助函数
    def strip_quotes(val):
        if isinstance(val, str):
            return val.strip('"').strip("'")
        return val
    
    # 直接从配置中构建替换映射
    # 所有配置项都使用 ${key} 格式作为占位符
    # 模板中已统一添加引号，这里只需去掉配置中的引号
    for key, value in config.items():
        if not key.startswith('_'):  # 跳过内部字段
            replace_map[key] = strip_quotes(value)
    
    # 确保一些关键字段有默认值
    if 'prefix' not in replace_map:
        replace_map['prefix'] = 'ddxq2'
    if 'server_id' not in replace_map:
        replace_map['server_id'] = '1'
    if 'server_type' not in replace_map:
        replace_map['server_type'] = 'game_server'
    if 'tcp_port' not in replace_map:
        replace_map['tcp_port'] = '18001'
    if 'http_port' not in replace_map:
        replace_map['http_port'] = '19001'
    if 'log_dir' not in replace_map:
        replace_map['log_dir'] = 'log'
    if 'merge_server_ids' not in replace_map:
        replace_map['merge_server_ids'] = '[]'
    if 'merge_server_time' not in replace_map:
        replace_map['merge_server_time'] = '{{1970,1,1},{0,0,0}}'
    if 'last_merge_server_ids' not in replace_map:
        replace_map['last_merge_server_ids'] = '[]'
    if 'open_time' not in replace_map:
        replace_map['open_time'] = '{{2025,1,1},{10,0,0}}'
    if 'auto_reload' not in replace_map:
        replace_map['auto_reload'] = 'true'
    
    # ip / game_host：与 read_merged_config 一致，缺省时使用本机 IP
    local_ip = get_local_ip()
    if 'ip' not in replace_map or not str(replace_map.get('ip', '')).strip():
        replace_map['ip'] = local_ip
    if 'game_host' not in replace_map or not str(replace_map.get('game_host', '')).strip():
        replace_map['game_host'] = replace_map.get('ip', local_ip)
    
    return replace_map


def generate_start_config(server_root: str, server_dir: str) -> Optional[Dict[str, str]]:
    """生成启动配置文件
    
    读取 default.config → project.config → user.config → kv.config → 替换模板 → 生成 sys.config
    
    优先级（从低到高）：default.config < project.config < user.config < kv.config
    
    Args:
        server_root: 服务器根目录
        server_dir: 服务器目录名（如 ddxq_game_s1）
    
    Returns:
        合并后的配置字典，如果失败返回 None
    """
    server_root_path = Path(server_root)
    config_path = get_server_manager_config_dir(server_root_path)
    run_path = server_root_path / 'run'
    
    # 服务器配置目录
    server_config_path = run_path / server_dir / 'config'
    kv_config_file = server_config_path / 'kv.config'
    sys_config_file = server_config_path / 'sys.config'
    
    # 检查 kv.config 是否存在
    if not kv_config_file.exists():
        return None
    
    # 合并配置：default.config < project.config < user.config < kv.config
    merged_config = read_merged_config(server_root, server_dir)
    
    # 根据服务器类型选择模板
    server_type = merged_config.get('server_type', 'game_server').strip('"').strip("'")
    template_file = get_template_file(config_path, server_type)
    
    if not template_file:
        return None
    
    with open(template_file, 'r', encoding='utf-8') as f:
        template_content = f.read()
    
    # 日志目录：拼上 run/<server_dir>/ 前缀，让日志收敛到具体服务目录下
    # 不再依赖 file:set_cwd 改变运行时工作目录（为了兼容 Erlang shell 的 c() 命令）
    def _normalize_run_log_path(raw: str, default_tail: str) -> str:
        """把配置里的日志路径统一成 run/<server_dir>/<tail>。
        形如 run/xxx/log 时只取第 3 段及之后，避免 default.config 中的模板值
        run/server/log 污染具体服务器的实际路径。
        """
        raw = (raw or '').strip('"').strip("'").strip()
        if raw.startswith('run/'):
            parts = raw.split('/', 2)
            tail = parts[2] if len(parts) > 2 and parts[2] else default_tail
        else:
            tail = raw or default_tail
        return f'run/{server_dir}/{tail}'

    merged_config['log_dir'] = _normalize_run_log_path(
        str(merged_config.get('log_dir', 'log')), 'log')

    # 角色日志目录（游戏服专用，模板里以 ${role_log} 引用）
    if 'role_log' in merged_config:
        merged_config['role_log'] = _normalize_run_log_path(
            str(merged_config.get('role_log', '')), 'log')
    
    # 构建替换映射
    replace_map = build_replace_map(merged_config)
    
    # 替换占位符（使用 ${xxx} 格式）
    output_content = template_content
    for key, value in replace_map.items():
        output_content = output_content.replace(f'${{{key}}}', str(value))
    
    # 检查是否有未替换的占位符
    unreplaced = re.findall(r'\$\{(\w+)\}', output_content)
    if unreplaced:
        print(f"[警告] 配置文件中有未替换的占位符: {set(unreplaced)}")
    
    # 生成最终配置文件 sys.config
    with open(sys_config_file, 'w', encoding='utf-8') as f:
        f.write(output_content)
    
    # 将服务器信息加入配置
    merged_config['_server_dir'] = server_dir
    merged_config['_config_file'] = str(sys_config_file)
    
    return merged_config
