package omctelnet

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"strings"
	"sync"
	"time"

	"be.ems/lib/dborm"
)

type TelnetHandler struct {
	ListenAddr string
	ListenPort uint16
	UserName   string
	Password   string
	AuthType   string
	MaxConnNum int
	TagNE      string
	ListenHost string

	connCount int
	mu        sync.Mutex
}

func (t *TelnetHandler) handleTelnetAuth(authType, userName, password string) bool {
	switch authType {
	case "local":
		if userName == t.UserName && password == t.Password {
			return true
		}
		return false
	case "radius", "omc":
		exist, err := dborm.XEngDB().Table("OMC_PUB.sysUser").Where("userName=? AND password=md5(?)", userName, password).Exist()
		if err != nil {
			return false
		}
		return exist

	default:
	}

	return false
}

func (t *TelnetHandler) StartTelnetServer() {
	listener, err := net.Listen("tcp", t.ListenHost)
	if err != nil {
		fmt.Println("Error starting Telnet server:", err)
		return
	}
	defer listener.Close()
	fmt.Println("Telnet server started on", t.ListenHost)

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Error accepting Telnet connection:", err)
			continue
		}

		t.mu.Lock()
		if t.connCount >= int(t.MaxConnNum) {
			t.mu.Unlock()
			msg := fmt.Sprintf("Connection limit reached (limit=%d). Try again later.\r\n", t.MaxConnNum)
			io.WriteString(conn, msg)
			conn.Close()
			continue
		}
		t.connCount++
		t.mu.Unlock()

		go t.handleTelnetConnection(conn)
	}
}

func (t *TelnetHandler) handleTelnetConnection(conn net.Conn) {
	defer func() {
		t.mu.Lock()
		t.connCount--
		t.mu.Unlock()
	}()
	defer conn.Close()

	reader := bufio.NewReader(conn)
	writer := bufio.NewWriter(conn)

	// 发送欢迎信息

	writer.WriteString(fmt.Sprintf("\r\nWelcome to the %s server!\r\n", strings.ToUpper(t.TagNE)))
	writer.Flush()

	// 请求用户名
	writer.WriteString("Username: ")
	writer.Flush()
	user, _ := reader.ReadString('\n')
	user = strings.TrimSpace(user)

	// 关闭回显模式
	writer.Write([]byte{255, 251, 1}) // IAC WILL ECHO
	writer.Flush()

	// 请求密码
	writer.WriteString("Password: ")
	writer.Flush()

	// 读取密码并清除控制序列
	var passBuilder strings.Builder
	for {
		b, err := reader.ReadByte()
		if err != nil {
			return
		}
		if b == '\n' || b == '\r' {
			break
		}
		if b == 255 { // IAC
			reader.ReadByte() // 忽略下一个字节
			reader.ReadByte() // 忽略下一个字节
		} else {
			passBuilder.WriteByte(b)
		}
	}
	pass := passBuilder.String()

	// 恢复回显模式
	writer.Write([]byte{255, 252, 1}) // IAC WONT ECHO
	writer.Flush()

	if t.handleTelnetAuth(t.AuthType, user, pass) {
		msg := fmt.Sprintf("\r\n\r\nLast login: %s from %s \r\n\r\n", time.Now().Format(time.RFC1123), conn.RemoteAddr())
		writer.WriteString(msg)
		writer.Flush()
		t.HandleCommands(user, t.TagNE, reader, writer)
	} else {
		writer.WriteString("\r\nAuthentication failed!\r\n")
		writer.Flush()
	}
}

// 处理命令输
func (t *TelnetHandler) HandleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer) {
	header := fmt.Sprintf("[%s@%s]> ", user, tag)
	clearLine := "\033[2K\r" // ANSI 转义序列，用于清除当前行
	for {
		var commandBuilder strings.Builder
		for {
			b, err := reader.ReadByte()
			if err != nil {
				return
			}
			if b == '\n' || b == '\r' {
				break
			}
			if b == '\xff' || b == '\xfe' || b == '\x01' {
				continue
			}
			if b == 127 { // 处理退格键
				if commandBuilder.Len() > 0 {
					// 手动截断字符串
					command := commandBuilder.String()
					command = command[:len(command)-1]
					commandBuilder.Reset()
					commandBuilder.WriteString(command)
					writer.WriteString("\b \b") // 回显退格
					writer.Flush()
				}
			} else {
				// 回显用户输入的字符
				writer.WriteByte(b)
				writer.Flush()
				commandBuilder.WriteByte(b)
			}
		}
		command := strings.TrimSpace(commandBuilder.String())

		// 处理其他命令
		switch command {
		case "hello":
			writer.WriteString("\r\nHello, world!\r\n")
		case "time":
			writer.WriteString(fmt.Sprintf("\r\nCurrent time: %s\r\n", time.Now().Format(time.RFC1123)))
		case "exit", "quit":
			writer.WriteString("\r\n\r\nGoodbye!\r\n")
			writer.Flush()
			return
		case "":
		default:
			writer.WriteString("\r\nUnknown command\r\n")
			writer.Flush()
		}
		writer.WriteString(clearLine + header)
		writer.Flush()
	}
}
