# -*- coding: utf-8 -*-
"""Project configuration model."""

from util.runtime import *

def _empty_config_data():
    """无项目时的默认配置结构，避免 get() 报错"""
    return {
        "workspace": {"server_root": "", "run_dir": ""},
        "database": {"host": "", "user": "", "password": "", "port": 3306},
        "server": {
            "prefix": "ddxq2", "login_server_node": "", "center_server_node": "",
            "default_server_id": "1", "server_type": "game_server", "server_name": "",
            "ip": get_local_ip(), "game_host": get_local_ip(), "cookie": "ddxq2-node",
        },
        "erlang": {"r25_path": "", "erl": "erl", "werl": "werl", "escript": "escript"},
        "login_db": {
            "name": "", "server_id": 900, "host": "", "port": 0,
            "user": "", "password": "",
        },
        "commands": {"rebar": REBAR3_CMD, "svn": "svn"},
        "terminal": {"launch_mode": "auto", "exe_path": ""},
    }


class Config:
    """项目配置管理类：读写当前打开项目下的 .server_manager/config/user.config（与项目一起走）。
    打开项目时会将软件目录下受管模板同步到 .server_manager/config，并保留项目自己的 user.config。
    支持“无项目”启动：project_root=None 时仅显示欢迎页；通过 open_project(path) 打开项目后加载该项目配置。
    """
    
    def __init__(self, project_root: Optional[Path] = None):
        if getattr(sys, 'frozen', False):
            self._exe_dir = Path(sys.executable).parent
            self._script_dir = self._exe_dir
        else:
            self._script_dir = SRC_DIR
            self._exe_dir = self._script_dir.parent.parent
        
        self.tool_dir = None
        self.user_config_path = None
        self.tool_config_path = None
        self.config_error = None
        self.data = _empty_config_data()
        
        if project_root is not None:
            self.open_project(Path(project_root))
        else:
            self.config_error = "未打开项目"
    
    def has_project(self) -> bool:
        """是否已打开有效项目（存在 .server_manager/config）"""
        if self.tool_dir is None:
            return False
        return get_server_manager_config_dir(self.tool_dir).is_dir()
    
    def open_project(self, project_root: Path) -> bool:
        """打开项目目录并同步受管配置模板到 .server_manager/config。成功返回 True。"""
        project_root = Path(project_root).resolve()
        cfg_dir, err = ensure_and_get_server_manager_config_dir(project_root)
        if not cfg_dir:
            self.config_error = err
            return False
        self.tool_dir = project_root
        self.user_config_path = cfg_dir / USER_CONFIG_FILE
        self.tool_config_path = self.user_config_path
        self.config_error = None
        self.data = self._load_config()
        return True
    
    def _find_server_root(self) -> Path:
        """查找有效的服务器根目录
        
        查找顺序：优先运行目录（当前工作目录），再考虑 exe/脚本所在位置。
        
        Returns:
            有效的服务器根目录路径，如果都找不到返回 None
        """
        candidates = [
            Path.cwd(),  # 运行目录优先
            self._exe_dir,
            self._script_dir,
        ]
        
        for path in candidates:
            if find_existing_default_config_path(path):
                return path
            if (path / "config" / PROJECT_CONFIG_FILE).exists():
                return path
            if (path / "config" / DEFAULT_CONFIG_FILE).exists():
                return path
            if (path / "config" / LEGACY_DEFAULT_CONFIG_FILE).exists():
                return path
        
        return None
    
    def _load_tool_config(self) -> dict:
        """加载 user.config 文件，兼容旧项目的历史用户配置文件。"""
        if self.user_config_path is None:
            return {}
        config_path = self.user_config_path
        if not config_path.exists():
            legacy_path = config_path.parent / LEGACY_USER_CONFIG_FILE
            if not legacy_path.exists():
                return {}
            config_path = legacy_path
        
        config = {}
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if not line or line.startswith('#'):
                        continue
                    if '=' in line:
                        key, value = line.split('=', 1)
                        config[key.strip()] = value.strip()
        except Exception:
            return {}
        return config
    
    def _save_tool_config(self, config: dict):
        """保存 user.config 文件。"""
        lines = [
            "# Server Manager config",
            "# 此文件配置工具运行所需的环境路径",
            "",
            "# === 工作目录配置 ===",
            f"server_root={config.get('server_root', '')}",
            f"run_dir={config.get('run_dir', '')}",
            "",
            "# === 启动窗口配置 ===",
            f"terminal_launch_mode={config.get('terminal_launch_mode', 'auto')}",
            f"terminal_exe_path={config.get('terminal_exe_path', '')}",
            "",
            "# === Erlang 配置 ===",
            f"r25_path={config.get('r25_path', '')}",
            "",
            "# === 数据库配置 ===",
            f"db_host={config.get('db_host', '')}",
            f"db_port={config.get('db_port', '3306')}",
            f"db_user={config.get('db_user', '')}",
            f"db_pass={config.get('db_pass', '')}",
            "",
            "# === 登录服数据库配置（远程连接用）===",
            f"login_db_name={config.get('login_db_name', '')}",
            f"login_db_server_id={config.get('login_db_server_id', '900')}",
            f"login_db_host={config.get('login_db_host', '')}",
            f"login_db_port={config.get('login_db_port', '0')}",
            f"login_db_user={config.get('login_db_user', '')}",
            f"login_db_pass={config.get('login_db_pass', '')}",
            "",
            "# === 服务器基础配置 ===",
            f"prefix={config.get('prefix', 'ddxq2')}",
            f"default_server_id={config.get('default_server_id', '1')}",
            f"server_type={config.get('server_type', 'game_server')}",
            f"server_name={config.get('server_name', '')}",
            f"login_node={config.get('login_node', '')}",
            f"center_node={config.get('center_node', '')}",
            f"cookie={config.get('cookie', 'ddxq2-node')}",
        ]
        
        config_path = self.user_config_path or self.tool_config_path
        if config_path is None:
            return
        config_path.parent.mkdir(parents=True, exist_ok=True)
        with open(config_path, 'w', encoding='utf-8') as f:
            f.write('\n'.join(lines))
    
    def _load_default_kv(self, server_root: str) -> dict:
        """从 default.config 和 project.config 读取默认/项目配置。"""
        if not server_root:
            return {}
        
        config = {}
        default_config_path = find_existing_default_config_path(server_root)
        if default_config_path:
            config.update(read_config_file(str(default_config_path)))

        project_config_path = get_project_config_path(server_root)
        if project_config_path.exists():
            config.update(read_config_file(str(project_config_path)))
        return config
    
    def _load_config(self):
        """加载配置，从 user.config 读取，空值从 project.config/default.config 补充。
        以当前已打开的项目目录（self.tool_dir）为 server_root 默认值，user.config 可覆盖。
        """
        if self.tool_dir is None or self.user_config_path is None:
            return self.data
        tool_cfg = self._load_tool_config()
        is_first_run = not self.user_config_path.exists()
        
        # 以当前项目目录为默认，user.config 可覆盖；project.config/default.config 可补充。
        default_kv = self._load_default_kv(str(self.tool_dir))
        server_root = tool_cfg.get('server_root', '') or default_kv.get('server_root', '') or str(self.tool_dir)
        if server_root != str(self.tool_dir):
            default_kv = self._load_default_kv(server_root)

        run_dir = tool_cfg.get('run_dir', '') or default_kv.get('run_dir', '')
        if not run_dir and server_root:
            run_dir = str(Path(server_root) / "run")
        
        # 首次运行时，创建运行目录
        if is_first_run and run_dir:
            run_path = Path(run_dir)
            if not run_path.exists():
                try:
                    run_path.mkdir(parents=True, exist_ok=True)
                except Exception:
                    pass
        
        # 辅助函数：优先使用 user.config 值，为空则使用 project.config/default.config 值
        def get_value(tool_key, default_key, fallback=''):
            val = tool_cfg.get(tool_key, '')
            if not val and default_kv:
                val = default_kv.get(default_key, fallback)
                # 去掉可能的引号
                if isinstance(val, str) and val.startswith("'") and val.endswith("'"):
                    val = val[1:-1]
            return val if val else fallback
        
        db_host = get_value('db_host', 'db_host', '')
        db_user = get_value('db_user', 'db_user', '')
        db_pass = get_value('db_pass', 'db_pass', '')
        db_port = get_value('db_port', 'db_port', '3306')
        cookie = get_value('cookie', 'cookie', 'ddxq2-node')
        login_db_name = get_value('login_db_name', 'login_db_name', '')
        login_db_server_id = get_value('login_db_server_id', 'login_db_server_id', '900')
        login_db_host = get_value('login_db_host', 'login_db_host', '')
        login_db_port = get_value('login_db_port', 'login_db_port', '0')
        login_db_user = get_value('login_db_user', 'login_db_user', '')
        login_db_pass = get_value('login_db_pass', 'login_db_pass', '')
        r25_path = get_value('r25_path', 'r25_path', '')
        terminal_launch_mode = (get_value('terminal_launch_mode', 'terminal_launch_mode', 'auto') or 'auto').strip().lower()
        terminal_exe_path = get_value('terminal_exe_path', 'terminal_exe_path', '')
        if not terminal_exe_path:
            legacy_exe = tool_cfg.get('terminal_custom_command', '') or default_kv.get('terminal_custom_command', '')
            legacy_cwd = tool_cfg.get('terminal_custom_cwd', '') or default_kv.get('terminal_custom_cwd', '')
            if legacy_exe and legacy_cwd and not any(sep in legacy_exe for sep in ('/', '\\')):
                legacy_path = Path(os.path.expandvars(os.path.expanduser(legacy_cwd))) / legacy_exe
                if legacy_path.is_file():
                    terminal_exe_path = str(legacy_path.resolve())
            if not terminal_exe_path:
                terminal_exe_path = legacy_exe
        
        # 服务器基础配置
        prefix = get_value('prefix', 'prefix', 'ddxq2')
        default_server_id = get_value('default_server_id', 'server_id', '1')
        server_type = get_value('server_type', 'server_type', 'game_server')
        server_name = get_value('server_name', 'server_name', '')
        local_ip = get_local_ip()
        login_node = get_value('login_node', 'login_node', '')
        center_node = get_value('center_node', 'center_node', '')
        
        config_data = {
            "workspace": {
                "server_root": server_root,
                "run_dir": run_dir,
            },
            "database": {
                "host": db_host,
                "user": db_user,
                "password": db_pass,
                "port": int(db_port) if db_port else 3306,
            },
            "server": {
                "prefix": prefix,
                "login_server_node": login_node,
                "center_server_node": center_node,
                "default_server_id": default_server_id,
                "server_type": server_type,
                "server_name": server_name,
                "ip": local_ip,
                "game_host": local_ip,
                "cookie": cookie,
            },
            "erlang": {
                "r25_path": r25_path,
                "erl": "erl",
                "werl": "werl",
                "escript": "escript"
            },
            "login_db": {
                "name": login_db_name,
                "server_id": int(login_db_server_id) if login_db_server_id else 900,
                "host": login_db_host,
                "port": int(login_db_port) if login_db_port else 0,
                "user": login_db_user,
                "password": login_db_pass,
            },
            "commands": {
                "rebar": REBAR3_CMD,
                "svn": "svn"
            },
            "terminal": {
                "launch_mode": terminal_launch_mode,
                "exe_path": terminal_exe_path,
            },
        }
        
        return config_data
    
    def has_default_kv(self) -> bool:
        """检查 default.config 是否存在，兼容旧项目的历史默认配置文件。"""
        server_root = self.get('workspace', 'server_root', default='')
        if not server_root:
            return False
        return find_existing_default_config_path(server_root) is not None
    
    def is_config_complete(self) -> bool:
        """检查工具配置是否完整"""
        # 检查必要的配置项
        db_host = self.get('database', 'host', default='')
        db_user = self.get('database', 'user', default='')
        prefix = self.get('server', 'prefix', default='')
        return bool(db_host and db_user and prefix)
    
    def save(self):
        """保存配置到 user.config"""
        if self.user_config_path is None:
            return
        local_ip = get_local_ip()
        self.set(local_ip, 'server', 'ip')
        self.set(local_ip, 'server', 'game_host')
        tool_cfg = {
            'server_root': self.get('workspace', 'server_root', default=''),
            'run_dir': self.get('workspace', 'run_dir', default=''),
            'r25_path': self.get('erlang', 'r25_path', default=''),
            'db_host': self.get('database', 'host', default=''),
            'db_port': str(self.get('database', 'port', default=3306)),
            'db_user': self.get('database', 'user', default=''),
            'db_pass': self.get('database', 'password', default=''),
            'login_db_name': self.get('login_db', 'name', default=''),
            'login_db_server_id': str(self.get('login_db', 'server_id', default=900)),
            'login_db_host': self.get('login_db', 'host', default=''),
            'login_db_port': str(self.get('login_db', 'port', default=0)),
            'login_db_user': self.get('login_db', 'user', default=''),
            'login_db_pass': self.get('login_db', 'password', default=''),
            'prefix': self.get('server', 'prefix', default='ddxq2'),
            'default_server_id': self.get('server', 'default_server_id', default='1'),
            'server_type': self.get('server', 'server_type', default='game_server'),
            'server_name': self.get('server', 'server_name', default=''),
            'login_node': self.get('server', 'login_server_node', default=''),
            'center_node': self.get('server', 'center_server_node', default=''),
            'cookie': self.get('server', 'cookie', default='ddxq2-node'),
            'terminal_launch_mode': self.get('terminal', 'launch_mode', default='auto'),
            'terminal_exe_path': self.get('terminal', 'exe_path', default=''),
        }
        self._save_tool_config(tool_cfg)
    
    def get(self, *keys, default=None):
        """获取配置项"""
        result = self.data
        for key in keys:
            if isinstance(result, dict) and key in result:
                result = result[key]
            else:
                return default
        return result
    
    def set(self, value, *keys):
        """设置配置项"""
        target = self.data
        for key in keys[:-1]:
            if key not in target:
                target[key] = {}
            target = target[key]
        target[keys[-1]] = value
    
    def is_configured(self) -> bool:
        """检查必要配置是否已设置"""
        server_root = self.get('workspace', 'server_root', default='')
        return bool(server_root and Path(server_root).exists())
    
    def get_missing_config(self) -> list:
        """获取缺失的必要配置项"""
        missing = []
        server_root = self.get('workspace', 'server_root', default='')
        if not server_root:
            missing.append("服务器根目录 (server_root)")
        elif not Path(server_root).exists():
            missing.append(f"服务器根目录不存在: {server_root}")
        return missing


def apply_terminal_launch_config(config: Config) -> None:
    """Apply project terminal launch settings to the process environment."""
    mode = (config.get('terminal', 'launch_mode', default='auto') or 'auto').strip().lower() or 'auto'
    terminal_exe = (config.get('terminal', 'exe_path', default='') or '').strip()

    os.environ['SERVER_MANAGER_TERMINAL'] = mode
    if terminal_exe:
        os.environ['SERVER_MANAGER_TERMINAL_EXE'] = terminal_exe
    else:
        os.environ.pop('SERVER_MANAGER_TERMINAL_EXE', None)
    os.environ.pop('SERVER_MANAGER_TERMINAL_COMMAND', None)
    os.environ.pop('SERVER_MANAGER_TERMINAL_CWD', None)
