# -*- coding: utf-8 -*-
"""Main tab views."""

from util.runtime import *
from util.utils import node_host_only, _server_id_sort_key
from models.config import Config, apply_terminal_launch_config
from controllers.workers import (
    CommandRunner,
    GroupedNodeStatusCheckWorker,
    NodeStatusCheckWorker,
    StopServerWorker,
)
from views.common import (
    NoWheelComboBox,
    NoWheelDateTimeEdit,
    NoWheelSpinBox,
    ServerIdTableItem,
    apply_button_style,
    make_line_icon,
    set_button_icon,
)
from views.console import OutputConsole
from views.dialogs import (
    ClearDatabaseDialog,
    KvConfigEditDialog,
    RemoteConnectDialog,
    ServerSelectDialog,
    ViewAccountsDialog,
)

class CreateServerTab(QWidget):
    """服务器创建页面 - 对应 create_server.bat"""
    
    def __init__(self, config: Config, console: OutputConsole):
        super().__init__()
        self.config = config
        self.console = console
        self.default_kv = {}
        self._initializing = True  # 初始化标志，防止启动时弹出提示
        self._load_default_kv()
        self.init_ui()
        self._initializing = False  # 初始化完成
    
    def _load_default_kv(self):
        """读取合并配置（user.config > project.config > default.config）"""
        server_root = self.config.get('workspace', 'server_root', default='')
        if not server_root:
            return
        
        self.default_kv = read_merged_config(server_root)
    
    def init_ui(self):
        layout = QVBoxLayout(self)
        layout.setSpacing(10)
        layout.setContentsMargins(10, 10, 10, 8)

        page = QWidget()
        page_layout = QVBoxLayout(page)
        page_layout.setContentsMargins(0, 0, 0, 0)
        page_layout.setSpacing(10)

        top_grid = QGridLayout()
        top_grid.setHorizontalSpacing(12)
        top_grid.setVerticalSpacing(10)

        type_group, type_layout = self._create_form_card("服务器配置", "server")
        type_layout.setSpacing(8)
        type_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        type_layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
        
        self.server_type_combo = NoWheelComboBox()
        self.server_type_combo.setMinimumHeight(32)
        self.server_type_combo.setMinimumWidth(200)
        
        types = [
            ("游戏服务器 (GameServer)", "game"),
            ("登录服务器 (LoginServer)", "login"),
            ("客户端服务器 (ClientServer)", "client"),
            ("中心服务器 (CenterServer)", "center"),
            ("跨服服务器 (CrossServer)", "cross"),
        ]
        
        for text, value in types:
            self.server_type_combo.addItem(text, value)
        
        type_layout.addRow("服务器类型：", self.server_type_combo)
        
        # 服务器ID
        self.server_id = NoWheelSpinBox()
        self.server_id.setRange(1, 10000)
        self.server_id.setValue(int(self.config.get('server', 'default_server_id', default='1')))
        self.server_id.setMinimumHeight(30)
        self.server_id.setMinimumWidth(150)
        self.server_id.valueChanged.connect(self._on_server_id_changed)
        self.server_id.editingFinished.connect(self._on_server_id_editing_finished)
        self.server_id_label = QLabel("服务器ID：")
        type_layout.addRow(self.server_id_label, self.server_id)
        
        # 服务器名称（仅游戏服需要）
        # 优先从 user.config 读取，读不到再从 project.config/default.config 读取
        default_server_name = self.config.get('server', 'server_name', default='')
        if not default_server_name:
            default_server_name = self.default_kv.get('server_name', '未命名服_1')
        # 提取服务器名称前缀（去掉最后的下划线和数字）
        self._server_name_prefix = self._extract_name_prefix(default_server_name)
        self.server_name_input = QLineEdit(default_server_name)
        self.server_name_input.setMinimumHeight(30)
        self.server_name_input.setPlaceholderText("例如：测试服_1")
        self.server_name_label = QLabel("服务器名称：")
        type_layout.addRow(self.server_name_label, self.server_name_input)
        
        # TCP 端口（游戏服、登录服、客户端服需要）
        default_tcp_port = int(self.default_kv.get('tcp_port', '18001'))
        self.tcp_port_input = NoWheelSpinBox()
        self.tcp_port_input.setRange(1, 65535)
        self.tcp_port_input.setValue(default_tcp_port)
        self.tcp_port_input.setMinimumHeight(30)
        self.tcp_port_input.setMinimumWidth(150)
        self.tcp_port_label = QLabel("TCP 端口：")
        type_layout.addRow(self.tcp_port_label, self.tcp_port_input)

        default_login_host = node_host_only(self.default_kv.get('login_host')) or get_local_ip()
        self.login_host_input = QLineEdit(default_login_host)
        self.login_host_input.setMinimumHeight(30)
        self.login_host_label = QLabel("登录服地址：")
        type_layout.addRow(self.login_host_label, self.login_host_input)

        default_login_http_port = int(self.default_kv.get('login_http_port', '19900') or 19900)
        self.login_http_port_input = NoWheelSpinBox()
        self.login_http_port_input.setRange(1, 65535)
        self.login_http_port_input.setValue(default_login_http_port)
        self.login_http_port_input.setMinimumHeight(30)
        self.login_http_port_input.setMinimumWidth(150)
        self.login_http_port_label = QLabel("登录服HTTP端口：")
        type_layout.addRow(self.login_http_port_label, self.login_http_port_input)

        # HTTP 端口（仅游戏服需要）
        default_http_port = int(self.default_kv.get('http_port', '19001'))
        self.http_port_input = NoWheelSpinBox()
        self.http_port_input.setRange(1, 65535)
        self.http_port_input.setValue(default_http_port)
        self.http_port_input.setMinimumHeight(30)
        self.http_port_input.setMinimumWidth(150)
        self.http_port_label = QLabel("HTTP 端口：")
        type_layout.addRow(self.http_port_label, self.http_port_input)

        default_auto_reload = str(self.default_kv.get('auto_reload', 'true')).strip().lower() == 'true'
        self.auto_reload_input = QCheckBox("启用自动热更")
        self.auto_reload_input.setChecked(default_auto_reload)
        self.auto_reload_input.setMinimumHeight(30)
        self.auto_reload_label = QLabel("自动热更：")
        type_layout.addRow(self.auto_reload_label, self.auto_reload_input)
        
        # 开服时间（游戏服、中心服、跨服服需要）
        self.open_time_input = NoWheelDateTimeEdit()
        self.open_time_input.setCalendarPopup(True)
        self.open_time_input.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        self.open_time_input.setDateTime(QDateTime.currentDateTime())
        self.open_time_input.setMinimumHeight(30)
        self.open_time_label = QLabel("开服时间：")
        type_layout.addRow(self.open_time_label, self.open_time_input)

        top_grid.addWidget(type_group, 0, 0)

        db_group, db_layout = self._create_form_card("数据库配置", "database")
        db_layout.setSpacing(8)
        db_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        db_layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
        
        self.use_default_db = QCheckBox("使用默认数据库配置")
        self.use_default_db.setChecked(True)
        self.use_default_db.setMinimumHeight(28)
        self.use_default_db.stateChanged.connect(self._toggle_db_fields)
        db_layout.addRow("", self.use_default_db)
        
        # 从 user.config (self.config) 读取数据库配置
        default_db_host = self.config.get('database', 'host', default='')
        default_db_user = self.config.get('database', 'user', default='')
        default_db_pass = self.config.get('database', 'password', default='')
        default_db_port = self.config.get('database', 'port', default=3306)
        
        self.db_host = QLineEdit(default_db_host)
        self.db_host.setMinimumHeight(32)
        self.db_user = QLineEdit(default_db_user)
        self.db_user.setMinimumHeight(32)
        self.db_pass = self._create_password_input(default_db_pass)
        self.db_pass.setMinimumHeight(32)
        
        self.db_port = NoWheelSpinBox()
        self.db_port.setRange(1, 65535)
        self.db_port.setValue(default_db_port)
        self.db_port.setMinimumHeight(32)

        db_layout.addRow("数据库主机：", self.db_host)
        db_layout.addRow("端口：", self.db_port)
        db_layout.addRow("用户名：", self.db_user)
        db_layout.addRow("密码：", self.db_pass)

        self.db_game_name_input = QLineEdit()
        self.db_game_name_input.setMinimumHeight(32)
        self.db_game_name_label = QLabel("db_game_name：")
        db_layout.addRow(self.db_game_name_label, self.db_game_name_input)

        self.db_log_name_input = QLineEdit()
        self.db_log_name_input.setMinimumHeight(32)
        self.db_log_name_label = QLabel("db_log_name：")
        db_layout.addRow(self.db_log_name_label, self.db_log_name_input)
        
        self._toggle_db_fields(Qt.CheckState.Checked.value)

        top_grid.addWidget(db_group, 0, 1)
        top_grid.setColumnStretch(0, 1)
        top_grid.setColumnStretch(1, 1)
        page_layout.addLayout(top_grid)

        node_group, node_layout = self._create_form_card("节点配置", "branch")
        node_layout.setSpacing(8)
        node_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        node_layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
        
        self.use_default_nodes = QCheckBox("使用默认节点配置")
        self.use_default_nodes.setChecked(True)
        self.use_default_nodes.setMinimumHeight(28)
        self.use_default_nodes.stateChanged.connect(self._toggle_node_fields)
        node_layout.addRow("", self.use_default_nodes)
        
        # 优先从 user.config 读取登录节点，读不到再从 project.config/default.config 读取
        default_login_node = self.config.get('server', 'login_server_node', default='')
        if not default_login_node:
            default_login_node = self.default_kv.get('login_node', '')
        if default_login_node.startswith("'") and default_login_node.endswith("'"):
            default_login_node = default_login_node[1:-1]
        self.login_node = QLineEdit(default_login_node)
        self.login_node.setMinimumHeight(30)
        self.login_node_label = QLabel("登录服节点：")
        
        # 优先从 user.config 读取中心服节点，读不到再从 project.config/default.config 读取
        default_center_node = self.config.get('server', 'center_server_node', default='')
        if not default_center_node:
            default_center_node = self.default_kv.get('center_node', '')
        if default_center_node.startswith("'") and default_center_node.endswith("'"):
            default_center_node = default_center_node[1:-1]
        self.center_node = QLineEdit(default_center_node)
        self.center_node.setMinimumHeight(30)
        self.center_node_label = QLabel("中心服节点：")

        self.node_row = QWidget()
        node_row_layout = QHBoxLayout(self.node_row)
        node_row_layout.setContentsMargins(0, 0, 0, 0)
        node_row_layout.setSpacing(12)

        self.login_node_wrap = QWidget()
        login_layout = QHBoxLayout(self.login_node_wrap)
        login_layout.setContentsMargins(0, 0, 0, 0)
        login_layout.setSpacing(8)
        login_layout.addWidget(self.login_node_label)
        login_layout.addWidget(self.login_node, 1)

        self.center_node_wrap = QWidget()
        center_layout = QHBoxLayout(self.center_node_wrap)
        center_layout.setContentsMargins(0, 0, 0, 0)
        center_layout.setSpacing(8)
        center_layout.addWidget(self.center_node_label)
        center_layout.addWidget(self.center_node, 1)

        node_row_layout.addWidget(self.login_node_wrap, 1)
        node_row_layout.addWidget(self.center_node_wrap, 1)
        node_layout.addRow("", self.node_row)
        
        self._toggle_node_fields(Qt.CheckState.Checked.value)
        
        # 根据服务器类型显示/隐藏中心服节点
        self.server_type_combo.currentIndexChanged.connect(self._on_server_type_changed)
        self._on_server_type_changed()
        
        page_layout.addWidget(node_group)

        action_row = QHBoxLayout()
        action_row.addStretch()
        reset_btn = QPushButton("重置")
        reset_btn.setFixedSize(110, 34)
        apply_button_style(reset_btn, "neutral")
        set_button_icon(reset_btn, "refresh", "#aab4c3", 16)
        reset_btn.clicked.connect(self.refresh_config)
        action_row.addWidget(reset_btn)

        create_btn = QPushButton("创建服务器")
        create_btn.setFixedSize(150, 34)
        apply_button_style(create_btn, "primary")
        set_button_icon(create_btn, "plus", "#242932", 16)
        create_btn.clicked.connect(self.create_server)
        action_row.addWidget(create_btn)
        page_layout.addLayout(action_row)
        page_layout.addStretch()

        layout.addWidget(page, 1)

    def _create_form_card(self, title: str, icon_kind: str):
        card = QFrame()
        card.setObjectName("createFormCard")
        card.setStyleSheet(
            """
            QFrame#createFormCard {
                background-color: #242932;
                border: 1px solid #3a4352;
                border-radius: 8px;
            }
            """
        )
        outer = QVBoxLayout(card)
        outer.setContentsMargins(18, 14, 18, 16)
        outer.setSpacing(16)

        header = QHBoxLayout()
        header.setContentsMargins(0, 0, 0, 0)
        header.setSpacing(8)
        icon = QLabel()
        icon.setPixmap(make_line_icon(icon_kind, "#4f8cff", 18).pixmap(18, 18))
        header.addWidget(icon)
        label = QLabel(title)
        label.setStyleSheet("color: #e8eef7; font-size: 14px; font-weight: 700;")
        header.addWidget(label)
        header.addStretch()
        outer.addLayout(header)

        body = QWidget()
        form = QFormLayout(body)
        form.setContentsMargins(0, 0, 0, 0)
        outer.addWidget(body, 1)
        return card, form
    
    def _create_password_input(self, default_value: str = '') -> QLineEdit:
        """创建带眼睛图标的密码输入框"""
        password_input = QLineEdit(default_value)
        password_input.setEchoMode(QLineEdit.EchoMode.Password)
        
        toggle_action = QAction(make_line_icon("eye", "#778398", 16), "", password_input)
        toggle_action.setToolTip("显示/隐藏密码")
        password_input.addAction(toggle_action, QLineEdit.ActionPosition.TrailingPosition)
        password_input.setProperty("password_visible", False)
        
        def toggle_visibility():
            visible = password_input.property("password_visible")
            if visible:
                password_input.setEchoMode(QLineEdit.EchoMode.Password)
                toggle_action.setIcon(make_line_icon("eye", "#778398", 16))
                password_input.setProperty("password_visible", False)
            else:
                password_input.setEchoMode(QLineEdit.EchoMode.Normal)
                toggle_action.setIcon(make_line_icon("eye_off", "#778398", 16))
                password_input.setProperty("password_visible", True)
        
        toggle_action.triggered.connect(toggle_visibility)
        return password_input
    
    def _extract_name_prefix(self, server_name: str) -> str:
        """提取服务器名称前缀（去掉最后的下划线和数字）
        
        例如：'文涛服_1' -> '文涛服'
              '测试服_123' -> '测试服'
              '未命名服_1' -> '未命名服'
        """
        if not server_name:
            return '未命名服'
        # 查找最后一个下划线的位置
        last_underscore = server_name.rfind('_')
        if last_underscore > 0:
            # 检查下划线后面是否是数字
            suffix = server_name[last_underscore + 1:]
            if suffix.isdigit():
                return server_name[:last_underscore]
        return server_name

    def _default_db_names(self, server_type: str = None, server_id: int = None) -> tuple:
        """根据当前类型和ID生成默认业务库/日志库名称。"""
        server_type = server_type or self.server_type_combo.currentData()
        server_id = server_id if server_id is not None else self.server_id.value()
        prefix = self.config.get('server', 'prefix', default='ddxq2') or 'ddxq2'
        type_prefix = {
            'game': 'game',
            'login': 'login',
            'center': 'center',
            'cross': 'cross',
            'client': 'client',
        }.get(server_type, server_type)
        return (
            f'{prefix}_{type_prefix}_s{server_id}',
            f'{prefix}_{type_prefix}_log_s{server_id}',
        )

    def _sync_db_name_inputs(self):
        """同步创建页显示的默认数据库名。"""
        if not hasattr(self, 'db_game_name_input'):
            return
        db_game_name, db_log_name = self._default_db_names()
        self.db_game_name_input.setText(db_game_name)
        self.db_log_name_input.setText(db_log_name)
    
    def _on_server_id_changed(self, value):
        """服务器ID变化时更新默认值"""
        # 更新服务器名称（使用配置的前缀）
        self.server_name_input.setText(f"{self._server_name_prefix}_{value}")
        # 更新端口
        self.tcp_port_input.setValue(18000 + value)
        self.http_port_input.setValue(19000 + value)
        self._sync_db_name_inputs()
    
    def _on_server_id_editing_finished(self):
        """服务器ID输入完成时检查范围"""
        server_type = self.server_type_combo.currentData()
        current_value = self.server_id.value()
        min_id = self.server_id.minimum()
        max_id = self.server_id.maximum()
        
        # 获取用户实际输入的文本（可能超出范围）
        text = self.server_id.lineEdit().text() if self.server_id.lineEdit() else str(current_value)
        try:
            input_value = int(text)
        except ValueError:
            return
        
        # 如果用户输入的值被自动修正了，说明超出了范围
        if input_value != current_value:
            type_names = {
                'game': '游戏服',
                'login': '登录服',
                'center': '中心服',
                'cross': '跨服服',
                'client': '客户端服',
            }
            type_name = type_names.get(server_type, server_type)
            QMessageBox.warning(
                self, "ID 超出范围",
                f"{type_name}的服务器ID范围为 {min_id} - {max_id}\n"
                f"输入值 {input_value} 超出范围，已自动修正为 {current_value}"
            )
    
    def _toggle_db_fields(self, state):
        enabled = state != Qt.CheckState.Checked.value
        self.db_host.setEnabled(enabled)
        self.db_user.setEnabled(enabled)
        self.db_pass.setEnabled(enabled)
        self.db_port.setEnabled(enabled)
    
    def _toggle_node_fields(self, state):
        enabled = state != Qt.CheckState.Checked.value
        self.login_node.setEnabled(enabled)
        self.center_node.setEnabled(enabled)
    
    def _on_server_type_changed(self):
        """根据服务器类型显示/隐藏配置项"""
        server_type = self.server_type_combo.currentData()
        
        # 根据服务器类型设置ID范围（从 default.config 读取）
        # 格式: {type}_id_min, {type}_id_max, {type}_id_default
        default_ranges = {
            'game': (100, 9999, 100),
            'login': (10, 100, 10),
            'center': (1, 10, 1),
            'cross': (10000, 20000, 10000),
            'client': (1, 10000, 1),
        }
        fallback = default_ranges.get(server_type, (1, 6000, 1))
        min_id = int(self.default_kv.get(f'{server_type}_id_min', fallback[0]))
        max_id = int(self.default_kv.get(f'{server_type}_id_max', fallback[1]))
        default_id = int(self.default_kv.get(f'{server_type}_id_default', fallback[2]))
        current_id = self.server_id.value()
        self.server_id.setRange(min_id, max_id)
        # 如果当前值超出范围，设置为默认值并提示用户
        if current_id < min_id or current_id > max_id:
            self.server_id.setValue(default_id)
            # 只在非初始化时显示提示
            if not self._initializing:
                type_names = {
                    'game': '游戏服',
                    'login': '登录服', 
                    'center': '中心服',
                    'cross': '跨服服',
                    'client': '客户端服',
                }
                type_name = type_names.get(server_type, server_type)
                QMessageBox.information(
                    self, "ID 范围调整",
                    f"{type_name}的服务器ID范围为 {min_id} - {max_id}\n"
                    f"原ID值 {current_id} 超出范围，已重置为 {default_id}"
                )
        
        # 根据模板配置决定显示哪些配置项
        # | 字段 | game | login | center | cross | client |
        # | server_name | ✅ | ❌ | ❌ | ❌ | ❌ |
        # | tcp_port | ✅ | ✅ | ❌ | ❌ | ✅ |
        # | http_port | ✅ | ❌ | ❌ | ❌ | ❌ |
        # | open_time | ✅ | ❌ | ✅ | ✅ | ❌ |
        # | login_node | ✅ | ❌ | ✅ | ❌ | ✅ |
        # | center_node | ✅ | ❌ | ❌ | ✅ | ❌ |
        
        show_server_name = server_type == 'game'
        show_tcp_port = server_type in ('game', 'login', 'client')
        show_client_login = server_type == 'client'
        show_http_port = server_type == 'game'
        show_auto_reload = True
        show_open_time = server_type in ('game', 'center', 'cross')
        show_login = server_type in ('game', 'client', 'center')
        show_center = server_type in ('game', 'cross')
        show_db_names = server_type in ('game', 'login', 'center', 'cross')

        if server_type == 'client':
            self.server_id_label.setText("连接服务器ID：")
            self.tcp_port_label.setText("连接服务器端口：")
        else:
            self.server_id_label.setText("服务器ID：")
            self.tcp_port_label.setText("TCP 端口：")
        
        # 服务器配置区域
        self.server_name_input.setVisible(show_server_name)
        self.server_name_label.setVisible(show_server_name)
        self.tcp_port_input.setVisible(show_tcp_port)
        self.tcp_port_label.setVisible(show_tcp_port)
        self.login_host_input.setVisible(show_client_login)
        self.login_host_label.setVisible(show_client_login)
        self.login_http_port_input.setVisible(show_client_login)
        self.login_http_port_label.setVisible(show_client_login)
        self.http_port_input.setVisible(show_http_port)
        self.http_port_label.setVisible(show_http_port)
        self.auto_reload_input.setVisible(show_auto_reload)
        self.auto_reload_label.setVisible(show_auto_reload)
        self.open_time_input.setVisible(show_open_time)
        self.open_time_label.setVisible(show_open_time)

        self.db_game_name_input.setVisible(show_db_names)
        self.db_game_name_label.setVisible(show_db_names)
        self.db_log_name_input.setVisible(show_db_names)
        self.db_log_name_label.setVisible(show_db_names)
        self._sync_db_name_inputs()
        
        # 节点配置区域
        self.login_node_wrap.setVisible(show_login)
        self.center_node_wrap.setVisible(show_center)
        self.node_row.setVisible(show_login or show_center)
        
        # 如果两个节点都不显示，隐藏整个默认复选框
        self.use_default_nodes.setVisible(show_login or show_center)
    
    def _get_existing_server_ids(self, server_type: str) -> set:
        """获取已存在的同类型服务器ID列表"""
        run_dir = self.config.get('workspace', 'run_dir', default='')
        server_root = self.config.get('workspace', 'server_root', default='')
        prefix = self.config.get('server', 'prefix', default='ddxq2')
        
        if not run_dir and server_root:
            run_dir = str(Path(server_root) / 'run')
        
        if not run_dir or not Path(run_dir).exists():
            return set()
        
        return get_existing_server_ids(run_dir, server_type, prefix)
    
    def create_server(self):
        """创建服务器"""
        server_type = self.server_type_combo.currentData()
        
        server_id = self.server_id.value()
        
        # 检查服务器ID是否已存在
        existing_ids = self._get_existing_server_ids(server_type)
        if server_id in existing_ids:
            type_names = {
                'game': '游戏服',
                'login': '登录服',
                'center': '中心服',
                'cross': '跨服服',
                'client': '客户端服',
            }
            type_name = type_names.get(server_type, server_type)
            QMessageBox.warning(
                self, "服务器ID已存在",
                f"{type_name} ID {server_id} 已存在！\n"
                f"已存在的{type_name}ID: {sorted(existing_ids)}\n\n"
                f"请选择其他ID。"
            )
            return
        
        # 获取数据库配置
        if self.use_default_db.isChecked():
            db_host = self.config.get('database', 'host', default='172.16.12.220')
            db_user = self.config.get('database', 'user', default='ddxqadmin')
            db_pass = self.config.get('database', 'password', default='ddxq@44168deabe63')
            db_port = self.config.get('database', 'port', default=3306)
        else:
            db_host = self.db_host.text()
            db_user = self.db_user.text()
            db_pass = self.db_pass.text()
            db_port = self.db_port.value()

        db_game_name = self.db_game_name_input.text().strip()
        db_log_name = self.db_log_name_input.text().strip()
        if server_type in ('game', 'login', 'center', 'cross'):
            missing_db_names = []
            if not db_game_name:
                missing_db_names.append('db_game_name')
            if not db_log_name:
                missing_db_names.append('db_log_name')
            if missing_db_names:
                QMessageBox.warning(
                    self,
                    '配置不完整',
                    '请填写：' + '、'.join(missing_db_names)
                )
                return
        
        # 获取节点配置 - 直接使用输入框中显示的值
        # 输入框的值已经在初始化时从 user.config 或 project.config/default.config 读取
        login_node = self.login_node.text().strip()
        center_node = self.center_node.text().strip()
        
        # 与 _on_server_type_changed 一致：何种类型需要哪些节点
        need_login = server_type in ('game', 'client', 'center')
        need_center = server_type in ('game', 'cross')
        missing_labels = []
        if need_login and not login_node:
            missing_labels.append('登录服节点')
        if need_center and not center_node:
            missing_labels.append('中心服节点')
        if missing_labels:
            QMessageBox.warning(
                self, '配置不完整',
                '请先配置：' + '、'.join(missing_labels) + '。\n\n'
                '可在本页对应输入框填写完整节点名，或到「项目设置」中填写登录服节点、中心服节点并保存后再创建。'
            )
            return
        
        # 获取服务器名称和端口配置
        server_name = self.server_name_input.text()
        tcp_port = self.tcp_port_input.value()
        http_port = self.http_port_input.value()
        login_host = self.login_host_input.text().strip()
        login_http_port = self.login_http_port_input.value()
        auto_reload = self.auto_reload_input.isChecked()
        if server_type == 'client' and not login_host:
            QMessageBox.warning(self, '配置不完整', '请填写登录服地址。')
            return
        
        # 获取开服时间
        open_time_dt = self.open_time_input.dateTime().toPyDateTime()
        open_time_str = open_time_dt.strftime("%Y-%m-%d %H:%M:%S")
        # Erlang 格式: {{年,月,日},{时,分,秒}}
        open_time_erl = f"{{{{{open_time_dt.year},{open_time_dt.month},{open_time_dt.day}}},{{{open_time_dt.hour},{open_time_dt.minute},{open_time_dt.second}}}}}"
        
        # 根据服务器类型生成确认信息
        type_names = {
            'game': '游戏服务器',
            'login': '登录服务器',
            'center': '中心服务器',
            'cross': '跨服服务器',
            'client': '客户端服务器',
        }
        type_name = type_names.get(server_type, server_type)
        
        # 根据模板配置决定显示哪些信息
        confirm_lines = [f'确定要创建 {type_name}？', f'ID: {server_id}']
        
        confirm_lines.append(f'自动热更: {"开启" if auto_reload else "关闭"}')
        if server_type in ('game', 'login', 'center', 'cross'):
            confirm_lines.append(f'db_game_name: {db_game_name}')
            confirm_lines.append(f'db_log_name: {db_log_name}')

        if server_type == 'game':
            confirm_lines.append(f'名称: {server_name}')
            confirm_lines.append(f'TCP端口: {tcp_port}')
            confirm_lines.append(f'HTTP端口: {http_port}')
            confirm_lines.append(f'开服时间: {open_time_str}')
            confirm_lines.append(f'登录节点: {login_node}')
            confirm_lines.append(f'中心节点: {center_node}')
        elif server_type == 'login':
            confirm_lines.append(f'TCP端口: {tcp_port}')
        elif server_type == 'center':
            confirm_lines.append(f'开服时间: {open_time_str}')
            confirm_lines.append(f'登录节点: {login_node}')
        elif server_type == 'cross':
            confirm_lines.append(f'开服时间: {open_time_str}')
            confirm_lines.append(f'中心节点: {center_node}')
        elif server_type == 'client':
            confirm_lines.append(f'连接服务器端口: {tcp_port}')
            confirm_lines.append(f'登录服地址: {login_host}')
            confirm_lines.append(f'登录服HTTP端口: {login_http_port}')
            confirm_lines.append(f'登录节点: {login_node}')
        
        # 确认创建
        reply = QMessageBox.question(
            self, '确认创建',
            '\n'.join(confirm_lines),
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )
        
        if reply == QMessageBox.StandardButton.Yes:
            self._do_create_server(server_type, server_id, db_host, db_user, db_pass, db_port, 
                                   db_game_name, db_log_name,
                                   login_node, center_node, server_name, tcp_port, http_port, login_host,
                                   login_http_port, open_time_erl, auto_reload)
    
    def _do_create_server(self, server_type, server_id, db_host, db_user, db_pass, db_port, 
                          db_game_name, db_log_name,
                          login_node, center_node, server_name, tcp_port, http_port, login_host,
                          login_http_port, open_time, auto_reload):
        """执行服务器创建 - 在 run/{server}/config/kv.config 创建差异化配置"""
        logger.info(f"创建服务器: type={server_type}, id={server_id}")
        logger.debug(f"数据库配置: host={db_host}, port={db_port}, user={db_user}")
        
        server_root = self.config.get('workspace', 'server_root', default='')
        run_dir = self.config.get('workspace', 'run_dir', default='')
        prefix = self.config.get('server', 'prefix', default='ddxq2')
        
        if not run_dir and server_root:
            run_dir = str(Path(server_root) / 'run')
        
        # 生成服务器目录名
        server_dir = generate_server_dir_name(prefix, server_type, server_id)
        
        # 检查是否已存在
        kv_config_file = Path(run_dir) / server_dir / 'config' / 'kv.config'
        overwrite = False
        if kv_config_file.exists():
            reply = QMessageBox.question(
                self, '服务器已存在',
                f'服务器 {server_dir} 已存在，是否覆盖配置？',
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
            )
            if reply != QMessageBox.StandardButton.Yes:
                return
            overwrite = True
        
        # 调用创建函数
        success, message, merged_config = create_server(
            server_root=server_root,
            run_dir=run_dir,
            server_type=server_type,
            server_id=server_id,
            prefix=prefix,
            db_host=db_host,
            db_user=db_user,
            db_pass=db_pass,
            db_port=db_port,
            db_game_name=db_game_name,
            db_log_name=db_log_name,
            login_node=login_node,
            center_node=center_node,
            server_name=server_name,
            tcp_port=tcp_port,
            http_port=http_port,
            login_host=login_host,
            login_http_port=login_http_port,
            open_time=open_time,
            auto_reload=auto_reload,
            overwrite=overwrite
        )
        
        if success:
            ip = get_local_ip()
            logger.info(f"服务器创建成功: {server_dir}")
            self.console.append_output(f"[成功] 差异化配置已创建: {kv_config_file}\n")
            if merged_config:
                self.console.append_output(f"[成功] 启动配置已生成: {merged_config.get('_config_file', '')}\n")
            
            self.console.append_output(f"\n[成功] 服务器创建完成!\n")
            self.console.append_output(f"  服务器目录: {server_dir}\n")
            self.console.append_output(f"  服务器ID: {server_id}\n")
            self.console.append_output(f"  IP: {ip}\n")
            if db_game_name:
                self.console.append_output(f"  db_game_name: {db_game_name}\n")
            if db_log_name:
                self.console.append_output(f"  db_log_name: {db_log_name}\n")
            if tcp_port:
                self.console.append_output(f"  TCP端口: {tcp_port}\n")
            
            QMessageBox.information(self, "成功", f"服务器 {server_dir} 创建完成！\n\n配置路径: run/{server_dir}/config/")
        else:
            logger.error(f"服务器创建失败: {server_dir}, 错误: {message}")
            self.console.append_output(f"[错误] {message}\n")
            QMessageBox.critical(self, "错误", message)
    
    def refresh_config(self):
        """刷新配置（当工具设置保存后调用）"""
        # 重新加载 user.config
        self.config.data = self.config._load_config()
        
        # 重新加载 default.config/project.config
        self._load_default_kv()
        
        # 更新数据库配置输入框
        db_host = self.config.get('database', 'host', default='')
        db_user = self.config.get('database', 'user', default='')
        db_pass = self.config.get('database', 'password', default='')
        db_port = self.config.get('database', 'port', default=3306)
        
        self.db_host.setText(str(db_host) if db_host else '')
        self.db_user.setText(str(db_user) if db_user else '')
        self.db_pass.setText(str(db_pass) if db_pass else '')
        self.db_port.setValue(int(db_port) if db_port else 3306)
        
        # 更新节点配置输入框
        login_node = self.config.get('server', 'login_server_node', default='')
        if not login_node:
            login_node = self.default_kv.get('login_node', '')
        if login_node.startswith("'") and login_node.endswith("'"):
            login_node = login_node[1:-1]
        center_node = self.config.get('server', 'center_server_node', default='')
        if not center_node:
            center_node = self.default_kv.get('center_node', '')
        if center_node.startswith("'") and center_node.endswith("'"):
            center_node = center_node[1:-1]
        
        self.login_node.setText(login_node)
        self.center_node.setText(center_node)
        self.login_host_input.setText(node_host_only(self.default_kv.get('login_host')) or get_local_ip())
        try:
            self.login_http_port_input.setValue(int(self.default_kv.get('login_http_port', '19900') or 19900))
        except ValueError:
            self.login_http_port_input.setValue(19900)
        
        # 更新服务器名称前缀
        server_name = self.config.get('server', 'server_name', default='')
        if not server_name:
            server_name = self.default_kv.get('server_name', '未命名服_1')
        self._server_name_prefix = self._extract_name_prefix(server_name)
        # 更新当前服务器名称（使用新前缀和当前ID）
        current_id = self.server_id.value()
        self.server_name_input.setText(f"{self._server_name_prefix}_{current_id}")
        self._sync_db_name_inputs()
