"""SSH 连接管理器"""
import io
import os
import stat
import paramiko
from typing import Optional
from .config import ServerConfig, ConfigManager


class SSHManager:
    def __init__(self, config_manager: ConfigManager):
        self.config_manager = config_manager
        self._client: Optional[paramiko.SSHClient] = None
        self._sftp: Optional[paramiko.SFTPClient] = None
        self._current_server: Optional[ServerConfig] = None

    @property
    def is_connected(self) -> bool:
        return self._client is not None and self._client.get_transport() is not None and self._client.get_transport().is_active()

    @property
    def current_server(self) -> Optional[ServerConfig]:
        return self._current_server if self.is_connected else None

    def connect(self, server_id: str) -> str:
        server = self.config_manager.get_server(server_id)
        if server is None:
            raise ValueError(f"服务器 ID '{server_id}' 不存在")

        self.disconnect()

        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        connect_kwargs = {
            "hostname": server.host,
            "port": server.port,
            "username": server.username,
            "timeout": 10,
        }

        if server.auth_type == "password":
            connect_kwargs["password"] = server.password
        elif server.auth_type == "key":
            key_path = os.path.expanduser(server.key_path)
            if not os.path.exists(key_path):
                raise FileNotFoundError(f"密钥文件不存在: {key_path}")
            if server.key_passphrase:
                connect_kwargs["key_filename"] = key_path
                connect_kwargs["passphrase"] = server.key_passphrase
            else:
                connect_kwargs["key_filename"] = key_path

        client.connect(**connect_kwargs)
        self._client = client
        self._current_server = server
        return f"已连接到 {server.name} ({server.host}:{server.port})"

    def disconnect(self) -> str:
        name = self._current_server.name if self._current_server else "未知"
        if self._sftp:
            try:
                self._sftp.close()
            except Exception:
                pass
            self._sftp = None
        if self._client:
            try:
                self._client.close()
            except Exception:
                pass
            self._client = None
        self._current_server = None
        return f"已断开连接: {name}"

    def _ensure_connected(self):
        if not self.is_connected:
            raise ConnectionError("未连接到任何服务器，请先使用 connect 工具连接")

    def _get_sftp(self) -> paramiko.SFTPClient:
        self._ensure_connected()
        if self._sftp is None or self._sftp.get_channel().closed:
            self._sftp = self._client.open_sftp()
        return self._sftp

    def exec_command(self, command: str, timeout: int = 30) -> dict:
        self._ensure_connected()
        stdin, stdout, stderr = self._client.exec_command(command, timeout=timeout)
        exit_code = stdout.channel.recv_exit_status()
        return {
            "stdout": stdout.read().decode("utf-8", errors="replace"),
            "stderr": stderr.read().decode("utf-8", errors="replace"),
            "exit_code": exit_code,
        }

    def upload_file(self, local_path: str, remote_path: str) -> str:
        sftp = self._get_sftp()
        sftp.put(local_path, remote_path)
        return f"已上传 {local_path} -> {remote_path}"

    def upload_content(self, content: str, remote_path: str) -> str:
        sftp = self._get_sftp()
        with sftp.open(remote_path, "w") as f:
            f.write(content)
        return f"已写入内容到 {remote_path}"

    def download_file(self, remote_path: str, local_path: str) -> str:
        sftp = self._get_sftp()
        os.makedirs(os.path.dirname(local_path) or ".", exist_ok=True)
        sftp.get(remote_path, local_path)
        return f"已下载 {remote_path} -> {local_path}"

    def read_file(self, remote_path: str) -> str:
        sftp = self._get_sftp()
        with sftp.open(remote_path, "r") as f:
            return f.read().decode("utf-8", errors="replace")

    def list_dir(self, remote_path: str = ".") -> list[dict]:
        sftp = self._get_sftp()
        result = []
        for attr in sftp.listdir_attr(remote_path):
            item = {
                "name": attr.filename,
                "size": attr.st_size,
                "is_dir": stat.S_ISDIR(attr.st_mode) if attr.st_mode else False,
                "permissions": oct(attr.st_mode & 0o777) if attr.st_mode else "unknown",
                "modified": attr.st_mtime,
            }
            result.append(item)
        return result

    def get_status(self) -> dict:
        if self.is_connected and self._current_server:
            return {
                "connected": True,
                "server_name": self._current_server.name,
                "host": self._current_server.host,
                "port": self._current_server.port,
                "username": self._current_server.username,
            }
        return {"connected": False}
