package ssh

import (
	"context"
	"fmt"
	"log"
	"time"
)

// SSHTools SSH工具实例，每个agent可以有独立的实例
type SSHTools struct {
	client *SshClient
}

// NewSSHTools 创建一个新的SSH工具实例
func NewSSHTools(host, username, password string) (*SSHTools, error) {
	if host == "" || username == "" || password == "" {
		return nil, fmt.Errorf("host, username 和 password 都是必需的")
	}

	client := NewClient(username, password, host)
	if err := client.Connect(); err != nil {
		log.Printf("%+v", client)
		return nil, fmt.Errorf("SSH 连接失败: %v", err)
	}

	return &SSHTools{
		client: client,
	}, nil
}

// Close 关闭SSH连接
func (st *SSHTools) Close() {
	if st != nil && st.client != nil {
		st.client.Close()
	}
}

// SSHExecuteRequest 执行远程命令请求
type SSHExecuteRequest struct {
	Server  string `json:"server,omitempty" jsonschema:"description=服务器名称，如果不指定则使用默认服务器"`
	Command string `json:"command" jsonschema:"description=要在远程服务器执行的命令,required"`
	Timeout int    `json:"timeout,omitempty" jsonschema:"description=超时时间（秒），默认60秒，最大300秒"`
}

// SSHExecuteResponse 执行远程命令响应
type SSHExecuteResponse struct {
	Output        string `json:"output" jsonschema:"description=命令输出内容（包含 stdout 和 stderr）"`
	ExecutionTime string `json:"execution_time" jsonschema:"description=执行时长"`
	ErrorMessage  string `json:"error_message,omitempty" jsonschema:"description=错误信息"`
}

// SSHExecute 在远程服务器执行命令
func (st *SSHTools) SSHExecute(ctx context.Context, req *SSHExecuteRequest) (*SSHExecuteResponse, error) {
	if st == nil || st.client == nil {
		return &SSHExecuteResponse{
			ErrorMessage: "SSH 客户端未初始化",
		}, nil
	}

	if req.Command == "" {
		return &SSHExecuteResponse{
			ErrorMessage: "command 参数是必需的",
		}, nil
	}

	// 1. 安全过滤
	if isDangerous(req.Command) {
		return &SSHExecuteResponse{
			ErrorMessage: "命令执行被拒绝：检测到危险命令",
		}, nil
	}

	// 2. 设置超时时间
	timeout := 60 * time.Second
	if req.Timeout > 0 && req.Timeout <= 300 {
		timeout = time.Duration(req.Timeout) * time.Second
	} else if req.Timeout > 300 {
		return &SSHExecuteResponse{
			ErrorMessage: "超时时间不能超过 300 秒",
		}, nil
	}

	// 3. 执行命令并计时
	startTime := time.Now()
	output, err := executeWithTimeout(st.client, req.Command, timeout)
	executionTime := time.Since(startTime)

	if err != nil {
		return &SSHExecuteResponse{
			Output:        string(output),
			ExecutionTime: executionTime.String(),
			ErrorMessage:  fmt.Sprintf("命令执行失败: %v", err),
		}, nil
	}

	return &SSHExecuteResponse{
		Output:        string(output),
		ExecutionTime: executionTime.String(),
	}, nil
}

// executeWithTimeout 带超时的命令执行
func executeWithTimeout(client *SshClient, cmd string, timeout time.Duration) ([]byte, error) {
	done := make(chan error, 1)
	output := make(chan []byte, 1)

	go func() {
		out, err := client.Run(cmd)
		output <- out
		done <- err
	}()

	select {
	case err := <-done:
		out := <-output
		return out, err
	case <-time.After(timeout):
		return nil, fmt.Errorf("命令执行超时（%v）", timeout)
	}
}

// SSHFileUploadRequest 文件上传请求
type SSHFileUploadRequest struct {
	LocalPath  string `json:"local_path" jsonschema:"description=本地文件路径,required"`
	RemotePath string `json:"remote_path" jsonschema:"description=远程文件路径,required"`
}

// SSHFileUploadResponse 文件上传响应
type SSHFileUploadResponse struct {
	Message      string `json:"message" jsonschema:"description=操作结果消息"`
	BytesWritten int64  `json:"bytes_written" jsonschema:"description=写入的字节数"`
	ErrorMessage string `json:"error_message,omitempty" jsonschema:"description=错误信息"`
}

// SSHFileUpload 上传文件到远程服务器
func (st *SSHTools) SSHFileUpload(ctx context.Context, req *SSHFileUploadRequest) (*SSHFileUploadResponse, error) {
	if st == nil || st.client == nil {
		return &SSHFileUploadResponse{
			ErrorMessage: "SSH 客户端未初始化",
		}, nil
	}

	if req.LocalPath == "" || req.RemotePath == "" {
		return &SSHFileUploadResponse{
			ErrorMessage: "local_path 和 remote_path 参数都是必需的",
		}, nil
	}

	n, err := st.client.CopyLocalFileToRemote(req.LocalPath, req.RemotePath)
	if err != nil {
		return &SSHFileUploadResponse{
			ErrorMessage: fmt.Sprintf("文件上传失败: %v", err),
		}, nil
	}

	return &SSHFileUploadResponse{
		Message:      fmt.Sprintf("成功上传 %d 字节到远程服务器", n),
		BytesWritten: n,
	}, nil
}

// SSHFileDownloadRequest 文件下载请求
type SSHFileDownloadRequest struct {
	RemotePath string `json:"remote_path" jsonschema:"description=远程文件路径,required"`
	LocalPath  string `json:"local_path" jsonschema:"description=本地文件路径,required"`
}

// SSHFileDownloadResponse 文件下载响应
type SSHFileDownloadResponse struct {
	Message      string `json:"message" jsonschema:"description=操作结果消息"`
	BytesRead    int64  `json:"bytes_read" jsonschema:"description=读取的字节数"`
	ErrorMessage string `json:"error_message,omitempty" jsonschema:"description=错误信息"`
}

// SSHFileDownload 从远程服务器下载文件
func (st *SSHTools) SSHFileDownload(ctx context.Context, req *SSHFileDownloadRequest) (*SSHFileDownloadResponse, error) {
	if st == nil || st.client == nil {
		return &SSHFileDownloadResponse{
			ErrorMessage: "SSH 客户端未初始化",
		}, nil
	}

	if req.RemotePath == "" || req.LocalPath == "" {
		return &SSHFileDownloadResponse{
			ErrorMessage: "remote_path 和 local_path 参数都是必需的",
		}, nil
	}

	n, err := st.client.CopyRemoteFileToLocal(req.RemotePath, req.LocalPath)
	if err != nil {
		return &SSHFileDownloadResponse{
			ErrorMessage: fmt.Sprintf("文件下载失败: %v", err),
		}, nil
	}

	return &SSHFileDownloadResponse{
		Message:   fmt.Sprintf("成功从远程服务器下载 %d 字节", n),
		BytesRead: n,
	}, nil
}

// SSHListDirRequest 列出远程目录请求
type SSHListDirRequest struct {
	RemotePath string `json:"remote_path" jsonschema:"description=远程目录路径,required"`
}

// SSHListDirResponse 列出远程目录响应
type SSHListDirResponse struct {
	Content      string `json:"content" jsonschema:"description=目录内容列表"`
	ErrorMessage string `json:"error_message,omitempty" jsonschema:"description=错误信息"`
}

// SSHListDir 列出远程目录的内容
func (st *SSHTools) SSHListDir(ctx context.Context, req *SSHListDirRequest) (*SSHListDirResponse, error) {
	if st == nil || st.client == nil {
		return &SSHListDirResponse{
			ErrorMessage: "SSH 客户端未初始化",
		}, nil
	}

	if req.RemotePath == "" {
		return &SSHListDirResponse{
			ErrorMessage: "remote_path 参数是必需的",
		}, nil
	}

	fileNames, err := st.client.ReadRemoteDir(req.RemotePath)
	if err != nil {
		return &SSHListDirResponse{
			ErrorMessage: fmt.Sprintf("列出目录失败: %v", err),
		}, nil
	}

	content := fmt.Sprintf("目录 %s 下的文件和文件夹：\n", req.RemotePath)
	for _, name := range fileNames {
		content += name + "\n"
	}

	return &SSHListDirResponse{
		Content: content,
	}, nil
}
