package telnet

import (
	"bytes"
	"fmt"
	"net"
	"strings"
	"time"
)

// ConnTelnet 连接telnet对象
type ConnTelnet struct {
	User     string `json:"user"`     // 主机用户名
	Addr     string `json:"addr"`     // 主机地址
	Port     int64  `json:"port"`     // telnet端口
	Password string `json:"password"` // 认证密码

	DialTimeOut time.Duration `json:"dialTimeOut"` // 连接超时断开

	Client     *net.Conn `json:"client"`
	LastResult string    `json:"lastResult"` // 记最后一次执行命令的结果
}

// NewClient 创建Telnet客户端
func (c *ConnTelnet) NewClient() (*ConnTelnet, error) {
	// IPV6地址协议
	proto := "tcp"
	if strings.Contains(c.Addr, ":") {
		proto = "tcp6"
	}
	addr := net.JoinHostPort(c.Addr, fmt.Sprint(c.Port))

	// 默认等待5s
	if c.DialTimeOut == 0 {
		c.DialTimeOut = 5 * time.Second
	}

	// 连接到 Telnet 服务器
	client, err := net.DialTimeout(proto, addr, c.DialTimeOut)
	if err != nil {
		return nil, err
	}

	// 进行登录
	if c.User != "" {
		time.Sleep(100 * time.Millisecond)
		client.Write([]byte(c.User + "\r\n"))
	}
	if c.Password != "" {
		time.Sleep(100 * time.Millisecond)
		client.Write([]byte(c.Password + "\r\n"))
	}
	// fmt.Fprintln(client, c.User)
	// fmt.Fprintln(client, c.Password)

	c.Client = &client

	// 排空连接登录的信息
	c.RunCMD("")
	return c, nil
}

// Close 关闭当前Telnet客户端
func (c *ConnTelnet) Close() {
	if c.Client != nil {
		(*c.Client).Close()
	}
}

// RunCMD 执行单次命令
func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
	if c.Client == nil {
		return "", fmt.Errorf("telnet client not connected")
	}
	conn := *c.Client

	// 写入命令
	if cmd != "" {
		if _, err := conn.Write([]byte(cmd)); err != nil {
			return "", err
		}
		time.Sleep(100 * time.Millisecond)
	}

	var buf bytes.Buffer
	tmp := make([]byte, 1024)
	for {
		// 读取命令消息
		n, err := conn.Read(tmp)
		if n == 0 || err != nil {
			tmp = nil
			break
		}

		tmpStr := string(tmp[:n])
		buf.WriteString(tmpStr)

		// 是否有终止符
		if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") {
			tmp = nil
			break
		}
	}
	defer buf.Reset()

	c.LastResult = buf.String()
	return c.LastResult, nil
}

// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns.
func (s *ConnTelnet) WindowChange(h, w int) error {
	if s.Client == nil {
		return fmt.Errorf("client is nil to content write failed")
	}
	conn := *s.Client

	// 需要确保接收方理解并正确处理发送窗口大小设置命令
	conn.Write([]byte{255, 251, 31})
	conn.Write([]byte{255, 250, 31, byte(w >> 8), byte(w & 0xFF), byte(h >> 8), byte(h & 0xFF), 255, 240})
	return nil
}

// NewClient 创建Telnet客户端会话对象
func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) {
	if c.Client == nil {
		return nil, fmt.Errorf("telnet client not connected")
	}
	s := &TelnetClientSession{
		Client: *c.Client,
	}
	// s.WindowChange(cols, rows)
	return s, nil
}
