package service

import (
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"
	"time"

	"be.ems/src/framework/cmd"
	"be.ems/src/framework/database/redis"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/resp"
	"be.ems/src/framework/telnet"
	"be.ems/src/modules/ws/model"
	"be.ems/src/modules/ws/processor"
)

// 实例化服务层 WSReceive 结构体
var NewWSReceive = &WSReceive{}

// WSReceive WebSocket消息接收处理 服务层处理
type WSReceive struct{}

// close 关闭服务连接
func (s *WSReceive) close(client *model.WSClient) {
	// 主动关闭
	resultByte, _ := json.Marshal(resp.OkMsg("user initiated closure"))
	client.MsgChan <- resultByte
	// 等待1s后关闭连接
	time.Sleep(1 * time.Second)
	NewWS.ClientClose(client.ID)
}

// Commont 接收通用业务处理
func (s *WSReceive) Commont(client *model.WSClient, reqMsg model.WSRequest) {
	// 必传requestId确认消息
	if reqMsg.RequestID == "" {
		msg := "message requestId is required"
		logger.Infof("ws Commont UID %d err: %s", client.BindUid, msg)
		msgByte, _ := json.Marshal(resp.ErrMsg(msg))
		client.MsgChan <- msgByte
		return
	}

	var resByte []byte
	var err error

	switch reqMsg.Type {
	case "close":
		s.close(client)
		return
	case "ping", "PING":
		resByte, _ := json.Marshal(resp.Ok(map[string]any{
			"requestId": reqMsg.RequestID,
			"data":      "PONG",
		}))
		client.MsgChan <- resByte
		client.MsgChan <- []byte("ws:pong")
		return
	case "ps":
		resByte, err = processor.GetProcessData(reqMsg.RequestID, reqMsg.Data)
	case "net":
		resByte, err = processor.GetNetConnections(reqMsg.RequestID, reqMsg.Data)
	case "ims_cdr", "smf_cdr", "smsc_cdr", "sgwc_cdr":
		resByte, err = processor.GetCDRConnect(reqMsg.RequestID, reqMsg.Data)
	case "amf_ue", "mme_ue":
		resByte, err = processor.GetUEConnect(reqMsg.RequestID, reqMsg.Data)
	case "upf_tf":
		resByte, err = processor.GetUPFTotalFlow(reqMsg.RequestID, reqMsg.Data)
	case "ne_state":
		resByte, err = processor.GetNeState(reqMsg.RequestID, reqMsg.Data)
	default:
		err = fmt.Errorf("message type %s not supported", reqMsg.Type)
	}

	if err != nil {
		logger.Warnf("ws Commont UID %d err: %s", client.BindUid, err.Error())
		msgByte, _ := json.Marshal(resp.ErrMsg(err.Error()))
		client.MsgChan <- msgByte
		return
	}
	if len(resByte) > 0 {
		client.MsgChan <- resByte
	}
}

// Shell 接收终端交互业务处理
func (s *WSReceive) Shell(client *model.WSClient, reqMsg model.WSRequest) {
	// 必传requestId确认消息
	if reqMsg.RequestID == "" {
		msg := "message requestId is required"
		logger.Infof("ws Shell UID %d err: %s", client.BindUid, msg)
		msgByte, _ := json.Marshal(resp.ErrMsg(msg))
		client.MsgChan <- msgByte
		return
	}

	var resByte []byte
	var err error

	switch reqMsg.Type {
	case "close":
		s.close(client)
		return
	case "ssh":
		// SSH会话消息接收写入会话
		command := reqMsg.Data.(string)
		// sshClientSession := client.ChildConn.(*ssh.SSHClientSession)
		// _, err = sshClientSession.Write(command)
		localClientSession := client.ChildConn.(*cmd.LocalClientSession)
		_, err = localClientSession.Write(command)
	case "resize":
		// SSH会话窗口重置
		msgByte, _ := json.Marshal(reqMsg.Data)
		var data struct {
			Cols int `json:"cols"`
			Rows int `json:"rows"`
		}
		err = json.Unmarshal(msgByte, &data)
		if err == nil {
			// sshClientSession := client.ChildConn.(*ssh.SSHClientSession)
			// err = sshClientSession.Session.WindowChange(data.Rows, data.Cols)
			localClientSession := client.ChildConn.(*cmd.LocalClientSession)
			localClientSession.WindowChange(data.Cols, data.Rows)
		}
	default:
		err = fmt.Errorf("message type %s not supported", reqMsg.Type)
	}

	if err != nil {
		logger.Warnf("ws Shell UID %d err: %s", client.BindUid, err.Error())
		msgByte, _ := json.Marshal(resp.ErrMsg(err.Error()))
		client.MsgChan <- msgByte
		if err == io.EOF {
			// 等待1s后关闭连接
			time.Sleep(1 * time.Second)
			client.StopChan <- struct{}{}
		}
		return
	}
	if len(resByte) > 0 {
		client.MsgChan <- resByte
	}
}

// ShellView 接收查看文件终端交互业务处理
func (s *WSReceive) ShellView(client *model.WSClient, reqMsg model.WSRequest) {
	// 必传requestId确认消息
	if reqMsg.RequestID == "" {
		msg := "message requestId is required"
		logger.Infof("ws ShellView UID %d err: %s", client.BindUid, msg)
		msgByte, _ := json.Marshal(resp.ErrMsg(msg))
		client.MsgChan <- msgByte
		return
	}

	var resByte []byte
	var err error

	switch reqMsg.Type {
	case "close":
		s.close(client)
		return
	case "cat", "tail":
		var command string
		if reqMsg.Type == "cat" {
			command, err = processor.ParseCat(reqMsg.Data)
		}
		if reqMsg.Type == "tail" {
			command, err = processor.ParseTail(reqMsg.Data)
		}
		if command != "" && err == nil {
			// sshClientSession := client.ChildConn.(*ssh.SSHClientSession)
			// _, err = sshClientSession.Write(command)
			localClientSession := client.ChildConn.(*cmd.LocalClientSession)
			_, err = localClientSession.Write(command)
		}
	case "ctrl-c":
		// 模拟按下 Ctrl+C
		// sshClientSession := client.ChildConn.(*ssh.SSHClientSession)
		// _, err = sshClientSession.Write("\u0003\n")
		localClientSession := client.ChildConn.(*cmd.LocalClientSession)
		_, err = localClientSession.Write("\u0003\n")
	case "resize":
		// 会话窗口重置
		msgByte, _ := json.Marshal(reqMsg.Data)
		var data struct {
			Cols int `json:"cols"`
			Rows int `json:"rows"`
		}
		err = json.Unmarshal(msgByte, &data)
		if err == nil {
			// sshClientSession := client.ChildConn.(*ssh.SSHClientSession)
			// err = sshClientSession.Session.WindowChange(data.Rows, data.Cols)
			localClientSession := client.ChildConn.(*cmd.LocalClientSession)
			localClientSession.WindowChange(data.Cols, data.Rows)
		}
	default:
		err = fmt.Errorf("message type %s not supported", reqMsg.Type)
	}

	if err != nil {
		logger.Warnf("ws ShellView UID %d err: %s", client.BindUid, err.Error())
		msgByte, _ := json.Marshal(resp.ErrMsg(err.Error()))
		client.MsgChan <- msgByte
		if err == io.EOF {
			// 等待1s后关闭连接
			time.Sleep(1 * time.Second)
			client.StopChan <- struct{}{}
		}
		return
	}
	if len(resByte) > 0 {
		client.MsgChan <- resByte
	}
}

// Telnet 接收终端交互业务处理
func (s *WSReceive) Telnet(client *model.WSClient, reqMsg model.WSRequest) {
	// 必传requestId确认消息
	if reqMsg.RequestID == "" {
		msg := "message requestId is required"
		logger.Infof("ws Shell UID %d err: %s", client.BindUid, msg)
		msgByte, _ := json.Marshal(resp.ErrMsg(msg))
		client.MsgChan <- msgByte
		return
	}

	var resByte []byte
	var err error

	switch reqMsg.Type {
	case "close":
		s.close(client)
		return
	case "telnet":
		// Telnet会话消息接收写入会话
		command := reqMsg.Data.(string)
		telnetClientSession := client.ChildConn.(*telnet.TelnetClientSession)
		_, err = telnetClientSession.Write(command)
	case "resize":
		// Telnet会话窗口重置
		msgByte, _ := json.Marshal(reqMsg.Data)
		var data struct {
			Cols int `json:"cols"`
			Rows int `json:"rows"`
		}
		err = json.Unmarshal(msgByte, &data)
		if err == nil {
			// telnetClientSession := client.ChildConn.(*telnet.TelnetClientSession)
			// _ = telnetClientSession.WindowChange(data.Rows, data.Cols)
		}
	default:
		err = fmt.Errorf("message type %s not supported", reqMsg.Type)
	}

	if err != nil {
		logger.Warnf("ws Shell UID %d err: %s", client.BindUid, err.Error())
		msgByte, _ := json.Marshal(resp.ErrMsg(err.Error()))
		client.MsgChan <- msgByte
		if err == io.EOF {
			// 等待1s后关闭连接
			time.Sleep(1 * time.Second)
			client.StopChan <- struct{}{}
		}
		return
	}
	if len(resByte) > 0 {
		client.MsgChan <- resByte
	}
}

// Redis 接收终端交互业务处理
func (s *WSReceive) Redis(client *model.WSClient, reqMsg model.WSRequest) {
	// 必传requestId确认消息
	if reqMsg.RequestID == "" {
		msg := "message requestId is required"
		logger.Infof("ws Shell UID %d err: %s", client.BindUid, msg)
		msgByte, _ := json.Marshal(resp.ErrMsg(msg))
		client.MsgChan <- msgByte
		return
	}

	var resByte []byte
	var err error

	switch reqMsg.Type {
	case "close":
		s.close(client)
		return
	case "redis":
		// Redis会话消息接收写入会话
		command := fmt.Sprint(reqMsg.Data)
		redisClientSession := client.ChildConn.(*redis.ConnRedis)
		output, err := redisClientSession.RunCMD(command)
		dataStr := ""
		if err != nil {
			dataStr = fmt.Sprintf("%s \r\n", err.Error())
		} else {
			// 获取结果的反射类型
			resultType := reflect.TypeOf(output)
			switch resultType.Kind() {
			case reflect.Slice:
				// 如果是切片类型需要进一步判断是否是 []string 或 []interface{}
				if resultType.Elem().Kind() == reflect.String {
					dataStr = fmt.Sprintf("%s \r\n", strings.Join(output.([]string), "\r\n"))
				} else if resultType.Elem().Kind() == reflect.Interface {
					arr := []string{}
					for _, v := range output.([]any) {
						arr = append(arr, fmt.Sprintf("%s", v))
					}
					dataStr = fmt.Sprintf("%s \r\n", strings.Join(arr, "\r\n"))
				}
			case reflect.Ptr:
				dataStr = "\r\n"
			case reflect.String, reflect.Int64:
				dataStr = fmt.Sprintf("%s \r\n", output)
			default:
				dataStr = fmt.Sprintf("%s \r\n", output)
			}
		}
		resByte, _ = json.Marshal(resp.Ok(map[string]any{
			"requestId": reqMsg.RequestID,
			"data":      dataStr,
		}))
	default:
		err = fmt.Errorf("message type %s not supported", reqMsg.Type)
	}

	if err != nil {
		logger.Warnf("ws Shell UID %d err: %s", client.BindUid, err.Error())
		msgByte, _ := json.Marshal(resp.ErrMsg(err.Error()))
		client.MsgChan <- msgByte
		if err == io.EOF {
			// 等待1s后关闭连接
			time.Sleep(1 * time.Second)
			client.StopChan <- struct{}{}
		}
		return
	}
	if len(resByte) > 0 {
		client.MsgChan <- resByte
	}
}
