# -*- 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 CommandTab(QWidget):
    """控制台操作页面 - 对应 command.bat"""
    
    def __init__(self, config: Config, console: OutputConsole):
        super().__init__()
        self.config = config
        self.console = console
        self.current_runner = None
        self.init_ui()
    
    def init_ui(self):
        layout = QVBoxLayout(self)
        layout.setSpacing(0)
        layout.setContentsMargins(10, 10, 10, 8)
        cards = QHBoxLayout()
        cards.setSpacing(18)
        
        # 编译操作区
        compile_group, compile_layout = self._create_command_card("编译与构建", "code")
        compile_layout.setHorizontalSpacing(12)
        compile_layout.setVerticalSpacing(12)
        
        # 编译代码
        compile_btn = self._create_button("编译代码", "编译游戏服务器代码", self.do_compile, "outline", "code")
        compile_layout.addWidget(compile_btn, 0, 0)
        
        # 快速编译模块
        quick_compile_btn = self._create_button("快速编译", "快速编译指定模块", self.do_quick_compile, "primary", "bolt")
        compile_layout.addWidget(quick_compile_btn, 0, 1)
        
        # 编译协议
        proto_btn = self._create_button("编译协议", "生成协议文件", self.do_protobuf, "outline", "shield")
        compile_layout.addWidget(proto_btn, 1, 0)
        
        # 编译Table
        table_btn = self._create_button("编译Table", "生成数据表", self.do_compile_table, "outline", "table")
        compile_layout.addWidget(table_btn, 1, 1)
        
        # 编译Tbllog
        tbllog_btn = self._create_button("编译Tbllog", "生成日志表", self.do_compile_tbllog, "outline", "file")
        compile_layout.addWidget(tbllog_btn, 2, 0)
        
        # 清理编译
        clear_btn = self._create_button("清理编译", "清理编译产物", self.do_clear, "danger-outline", "trash")
        compile_layout.addWidget(clear_btn, 2, 1)
        
        cards.addWidget(compile_group, 1)
        
        # 运行操作区
        run_group, run_layout = self._create_command_card("服务器运行", "server")
        run_layout.setHorizontalSpacing(12)
        run_layout.setVerticalSpacing(12)
        
        # 运行服务器
        run_btn = self._create_button("运行服务器", "选择并运行服务器", self.do_run, "primary", "play")
        run_layout.addWidget(run_btn, 0, 0)
        
        # 快速启动
        quick_btn = self._create_button("快速启动", "快速启动服务器", self.do_quick_start, "outline", "rocket")
        run_layout.addWidget(quick_btn, 0, 1)
        
        # 连接节点
        remsh_btn = self._create_button("连接节点", "远程连接服务器节点", self.do_remsh, "outline", "network")
        run_layout.addWidget(remsh_btn, 1, 0)
        
        # 查看账号
        accounts_btn = self._create_button("查看账号", "查看服务器玩家账号", self.do_view_accounts, "outline", "user")
        run_layout.addWidget(accounts_btn, 1, 1)
        
        # 停止服务器：等节点完全离线后自动关闭由本工具启动的相关窗口
        stop_btn = self._create_button(
            "停止服务器",
            "停止服务器，等待节点完全离线后关闭由本工具启动的相关窗口",
            self.do_stop_server,
            "danger-outline",
            "stop",
        )
        run_layout.addWidget(stop_btn, 2, 0)
        
        # 服务器清档
        clear_btn = self._create_button("服务器清档", "删除游戏库和日志库", self.do_clear_database, "danger-outline", "trash")
        run_layout.addWidget(clear_btn, 2, 1)
        
        cards.addWidget(run_group, 1)
        
        # SVN 操作
        svn_group, svn_layout = self._create_command_card("版本控制", "branch", grid=False)
        svn_layout.setSpacing(12)
        
        svn_layout.addStretch(1)
        svn_update_btn = self._create_button("SVN 更新", "更新代码", self.do_svn_update, "green", "download")
        svn_update_btn.setMinimumHeight(56)
        svn_update_btn.setMinimumWidth(210)
        svn_layout.addWidget(svn_update_btn)
        svn_layout.addStretch(1)
        
        cards.addWidget(svn_group, 0)
        layout.addLayout(cards)
        layout.setSizeConstraint(QVBoxLayout.SizeConstraint.SetMinAndMaxSize)

    def _create_command_card(self, title: str, icon_kind: str, grid: bool = True):
        card = QFrame()
        card.setObjectName("commandCard")
        card.setStyleSheet(
            """
            QFrame#commandCard {
                background-color: #242932;
                border: 1px solid #3a4352;
                border-radius: 8px;
            }
            """
        )
        outer = QVBoxLayout(card)
        outer.setContentsMargins(18, 16, 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", 20).pixmap(20, 20))
        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()
        body_layout = QGridLayout(body) if grid else QVBoxLayout(body)
        body_layout.setContentsMargins(0, 0, 0, 0)
        outer.addWidget(body, 1)
        return card, body_layout
    
    def _create_button(self, text, tooltip, callback, variant="neutral", icon_kind=None):
        variant_map = {
            "green": "success",
            "danger-outline": "danger",
        }
        btn = QPushButton(text)
        btn.setToolTip(tooltip)
        btn.clicked.connect(callback)
        btn.setMinimumHeight(40)
        btn.setMinimumWidth(148)
        apply_button_style(btn, variant_map.get(variant, variant))
        if icon_kind:
            icon_color = "#242932" if variant in ("primary", "green") else ("#ff5c6a" if variant == "danger-outline" else "#c6d7ef")
            set_button_icon(btn, icon_kind, icon_color, 18)
        return btn
    
    def _run_command(self, cmd, new_window=False):
        """执行命令"""
        server_root = self.config.get('workspace', 'server_root', default='')
        if not server_root:
            server_root = str(Path.cwd())
        self.current_runner = CommandRunner(cmd, cwd=server_root, start_new_window=new_window)
        self.current_runner.output_signal.connect(self.console.append_output)
        self.current_runner.start()
    
    def _get_erl_path(self) -> str:
        """获取配置的 Erlang 路径"""
        return self.config.get('erlang', 'r25_path', default='')
    
    def _get_rebar3(self) -> str:
        """获取 rebar3 命令（使用配置的 Erlang 版本）"""
        server_root = self.config.get('workspace', 'server_root', default='')
        if not server_root:
            server_root = str(Path.cwd())
        return get_rebar3_cmd(server_root, self._get_erl_path())
    
    def _get_escript(self) -> str:
        """获取 escript 命令（使用配置的 Erlang 版本）"""
        return get_escript_cmd(self._get_erl_path())
    
    def do_svn_update(self):
        self._run_command("svn update")
    
    def do_compile(self):
        self._run_command(f"{self._get_rebar3()} as game_server_dev compile")
    
    def do_protobuf(self):
        self._run_command(f"{self._get_rebar3()} protobuf compile -a game_server")
    
    def do_compile_table(self):
        self._run_command(f"{self._get_rebar3()} cache compile -a game_server")
    
    def do_compile_tbllog(self):
        self._run_command(f"{self._get_rebar3()} tbllog compile")
    
    def do_clear(self):
        reply = QMessageBox.question(
            self, '确认', '确定要清理编译产物吗？',
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            self._run_command(f"{self._get_rebar3()} clean")
    
    def do_quick_compile(self):
        """快速编译指定模块"""
        from PyQt6.QtWidgets import QInputDialog
        
        module_name, ok = QInputDialog.getText(
            self, '快速编译', 
            '请输入要编译的模块名（不含.erl后缀）:',
            text=''
        )
        
        if ok and module_name.strip():
            module_name = module_name.strip()
            escript = self._get_escript()
            cmd = f'"{escript}" shell/es/emake.escript 1 {module_name} && "{escript}" shell/es/emake.escript 2 {module_name}'
            
            self.console.append_output(f"\n[快速编译] 模块: {module_name}\n")
            self._run_command(cmd)
    
    def do_run(self):
        """运行服务器（使用 rebar3 shell）"""
        dialog = ServerSelectDialog(self.config, "运行服务器", self)
        if dialog.exec() == QDialog.DialogCode.Accepted:
            server = dialog.selected_server
            if server:
                server_root = self.config.get('workspace', 'server_root', default='')
                run_dir = self.config.get('workspace', 'run_dir', default='')
                cookie = self.config.get('server', 'cookie', default='ddxq2-node')
                
                if not run_dir and server_root:
                    run_dir = str(Path(server_root) / 'run')
                
                # 检查节点是否已在线
                from services.commands import check_node_status
                self.console.append_output(f"[检查] 正在检查节点 {server} 是否在线...\n")
                is_online = check_node_status(server, cookie, erl_path=self._get_erl_path())
                
                # 更新全局缓存
                cache = get_node_status_cache()
                cache.set(server, is_online)
                
                if is_online:
                    # 节点已在线，提示用户并弹出连接对话框
                    reply = QMessageBox.question(
                        self, '节点已在线',
                        f'服务器 {server} 已经在运行中。\n\n是否要连接到该节点？',
                        QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
                    )
                    if reply == QMessageBox.StandardButton.Yes:
                        # 弹出连接对话框
                        remsh_dialog = RemoteConnectDialog(self.config, self, initial_tab='local', console=self.console)
                        remsh_dialog.node_input.setText(server)
                        remsh_dialog.ip_input.setText(get_local_ip())
                        if remsh_dialog.exec() == QDialog.DialogCode.Accepted:
                            cmd = build_remsh_command(remsh_dialog.node_name, remsh_dialog.cookie, remsh_dialog.target_ip, erl_path=self._get_erl_path())
                            remsh_title = f"REMSH {server}"
                            launch_info = run_cmd_in_new_window(
                                cmd,
                                server_root,
                                remsh_title,
                                self._get_erl_path(),
                                **get_terminal_launch_options(self.config),
                            )
                            register_launched_window(server, 'remsh', remsh_title, launch_info)
                    return
                
                # rebar3 模式需要在服务器根目录运行（rebar.config 和 _build 在那里）
                cmd = build_start_command(server_root, server, cookie, use_rebar=True, erl_path=self._get_erl_path())
                self.console.append_output(f"[命令] {cmd}\n")
                self.console.append_output(f"[目录] {server_root}\n")
                server_title = f"SERVER {server}"
                launch_info = run_cmd_in_new_window(
                    cmd,
                    server_root,
                    server_title,
                    self._get_erl_path(),
                    **get_terminal_launch_options(self.config),
                )
                register_launched_window(server, 'server', server_title, launch_info)
                self.console.append_output(f"[服务器] 正在启动 {server}（rebar3 模式）...\n")
                
                # 延迟检查启动状态并更新缓存
                self._schedule_status_check(server, cookie)
    
    def do_quick_start(self):
        """快速启动（直接使用 erl）"""
        dialog = ServerSelectDialog(self.config, "快速启动", self)
        if dialog.exec() == QDialog.DialogCode.Accepted:
            server = dialog.selected_server
            if server:
                server_root = self.config.get('workspace', 'server_root', default='')
                cookie = self.config.get('server', 'cookie', default='ddxq2-node')
                
                # 检查节点是否已在线
                from services.commands import check_node_status
                self.console.append_output(f"[检查] 正在检查节点 {server} 是否在线...\n")
                is_online = check_node_status(server, cookie, erl_path=self._get_erl_path())
                
                # 更新全局缓存
                cache = get_node_status_cache()
                cache.set(server, is_online)
                
                if is_online:
                    # 节点已在线，提示用户并弹出连接对话框
                    reply = QMessageBox.question(
                        self, '节点已在线',
                        f'服务器 {server} 已经在运行中。\n\n是否要连接到该节点？',
                        QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
                    )
                    if reply == QMessageBox.StandardButton.Yes:
                        # 弹出连接对话框
                        remsh_dialog = RemoteConnectDialog(self.config, self, initial_tab='local', console=self.console)
                        remsh_dialog.node_input.setText(server)
                        remsh_dialog.ip_input.setText(get_local_ip())
                        if remsh_dialog.exec() == QDialog.DialogCode.Accepted:
                            cmd = build_remsh_command(remsh_dialog.node_name, remsh_dialog.cookie, remsh_dialog.target_ip, erl_path=self._get_erl_path())
                            remsh_title = f"REMSH {server}"
                            launch_info = run_cmd_in_new_window(
                                cmd,
                                server_root,
                                remsh_title,
                                self._get_erl_path(),
                                **get_terminal_launch_options(self.config),
                            )
                            register_launched_window(server, 'remsh', remsh_title, launch_info)
                    return
                
                # 统一使用 server_root 作为工作目录
                # erl/rebar3 需要在根目录找到 _build
                # 日志通过 sys.config 配置为 run/<服务器名称>/log，不再修改 Erlang 工作目录
                cmd = build_start_command(server_root, server, cookie, use_rebar=False, erl_path=self._get_erl_path())
                self.console.append_output(f"[命令] {cmd}\n")
                self.console.append_output(f"[目录] {server_root}\n")
                server_title = f"SERVER {server}"
                launch_info = run_cmd_in_new_window(
                    cmd,
                    server_root,
                    server_title,
                    self._get_erl_path(),
                    **get_terminal_launch_options(self.config),
                )
                register_launched_window(server, 'server', server_title, launch_info)
                self.console.append_output(f"[服务器] 正在快速启动 {server}（erl 模式）...\n")
                
                # 延迟检查启动状态并更新缓存
                self._schedule_status_check(server, cookie)
    
    def _schedule_status_check(self, server_name: str, cookie: str, retry_count: int = 0):
        """延迟检查服务器启动状态并更新缓存
        
        Args:
            server_name: 服务器名称
            cookie: Erlang cookie
            retry_count: 当前重试次数（最多10次）
        """
        from services.commands import check_node_status
        
        max_retries = 10
        
        def do_check():
            is_online = check_node_status(server_name, cookie, erl_path=self._get_erl_path())
            cache = get_node_status_cache()
            cache.set(server_name, is_online)
            
            if is_online:
                self.console.append_output(f"[状态] 服务器 {server_name} 已启动 🟢\n")
            else:
                current_retry = retry_count + 1
                if current_retry < max_retries:
                    self.console.append_output(f"[状态] 服务器 {server_name} 启动中... (检查 {current_retry}/{max_retries})\n")
                    # 继续等待，再次检查
                    self._schedule_status_check(server_name, cookie, current_retry)
                else:
                    self.console.append_output(f"[状态] 服务器 {server_name} 启动超时，请检查启动日志 ⚪\n")
        
        QTimer.singleShot(5000, do_check)
    
    def do_remsh(self):
        """远程连接"""
        dialog = RemoteConnectDialog(self.config, self, initial_tab='local', console=self.console)
        if dialog.exec() == QDialog.DialogCode.Accepted:
            node_name = dialog.node_name
            target_ip = dialog.target_ip
            cookie = dialog.cookie
            
            server_root = self.config.get('workspace', 'server_root', default='')
            cmd = build_remsh_command(node_name, cookie, target_ip, erl_path=self._get_erl_path())
            
            # 确定显示的目标节点名
            if '@' in node_name:
                target_node = node_name
            else:
                target_node = f"{node_name}@{target_ip}" if target_ip else f"{node_name}@{get_local_ip()}"
            
            remsh_title = f"REMSH {target_node}"
            launch_info = run_cmd_in_new_window(
                cmd,
                server_root,
                remsh_title,
                self._get_erl_path(),
                **get_terminal_launch_options(self.config),
            )
            register_launched_window(target_node, 'remsh', remsh_title, launch_info)
            self.console.append_output(f"[远程连接] 正在连接到 {target_node}...\n")
    
    def do_stop_server(self):
        """停止服务器：等节点完全离线后，关闭由本工具启动的相关窗口。"""
        if getattr(self, '_stop_worker', None) is not None and self._stop_worker.isRunning():
            QMessageBox.information(self, "提示", "当前已有停止任务正在执行，请稍候")
            return
        
        dialog = ServerSelectDialog(self.config, "停止服务器", self)
        if dialog.exec() != QDialog.DialogCode.Accepted:
            return
        server = dialog.selected_server
        if not server:
            return
        
        reply = QMessageBox.question(
            self, '确认停止',
            f'确定要停止服务器 {server} 吗？\n\n'
            f'停止后会等待节点完全离线，并关闭由本工具启动的相关窗口（服务进程窗口、远程连接窗口）。',
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )
        if reply != QMessageBox.StandardButton.Yes:
            return
        
        cookie = self.config.get('server', 'cookie', default='ddxq2-node')
        logger.info(f"停止服务器（控制台）: {server}")
        
        worker = StopServerWorker(
            server, cookie, erl_path=self._get_erl_path(), parent=self,
        )
        worker.progress_signal.connect(self.console.append_output)
        worker.finished_signal.connect(
            lambda ok, msg, s=server: self._on_stop_server_finished(s, ok, msg)
        )
        worker.finished.connect(worker.deleteLater)
        worker.finished.connect(lambda w=worker: setattr(self, '_stop_worker', None)
                                if getattr(self, '_stop_worker', None) is w else None)
        self._stop_worker = worker
        worker.start()
    
    def _on_stop_server_finished(self, server: str, is_success: bool, message: str):
        """停止服务器结束回调：更新状态缓存并给出提示。"""
        if is_success:
            cache = get_node_status_cache()
            cache.set_offline(server)
            self.console.append_output(f"[成功] {message}\n")
            logger.info(f"服务器停止成功: {server}")
        else:
            self.console.append_output(f"[失败] {message}\n")
            logger.warning(f"服务器停止失败: {server} - {message}")
            QMessageBox.warning(self, "停止失败", message)
    
    def do_view_accounts(self):
        """查看服务器账号"""
        dialog = ViewAccountsDialog(self.config, self)
        dialog.exec()
    
    def do_clear_database(self):
        """服务器清档"""
        dialog = ClearDatabaseDialog(self.config, self)
        if dialog.exec() == QDialog.DialogCode.Accepted:
            if dialog.result_info:
                self.console.append_output(f"[清档] {dialog.result_info}\n")
