package trace

import (
	"fmt"
	"net"
	"net/http"
	"strings"
	"time"

	"nms_nbi/lib/core/conf"
	"nms_nbi/lib/core/utils/ctx"
	"nms_nbi/lib/core/vo/result"
	"nms_nbi/lib/dborm"
	"nms_nbi/lib/log"
	"nms_nbi/restagent/config"
	"nms_nbi/src/framework/utils/cmd"
	"nms_nbi/src/framework/utils/ssh"
)

var (
	UriTcpdumpTask       = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask"
	CustomUriTcpdumpTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" // decode message api

	UriTcpdumpPcapDownload       = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload"
	CustomUriTcpdumpPcapDownload = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" // decode message api

	UriTcpdumpNeUPFTask       = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask"
	CustomUriTcpdumpNeUPFTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" // decode message api
)

// NeInfo 网元信息
func NeInfo(neType, neId string) (*dborm.NeInfo, error) {
	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		return nil, err
	}
	if neInfo == nil || neInfo.Ip == "" {
		return nil, fmt.Errorf("not ne_info or not IP")
	}
	return neInfo, nil
}

// TcpdumpNeTask 网元发送执行 pcap
func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) {
	var body struct {
		NeType  string `json:"neType"`  // 网元类型
		NeId    string `json:"neId"`    // 网元ID
		Timeout int    `json:"timeout"` // 超时时间
		Cmd     string `json:"cmd"`     // 命令
	}
	err := ctx.ShouldBindJSON(r, &body)
	if err != nil || body.NeType == "" || body.NeId == "" || body.Timeout < 5 || body.Cmd == "" {
		ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
		return
	}

	neInfo, err := NeInfo(body.NeType, body.NeId)
	if err != nil {
		ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		return
	}

	filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli())
	fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli())
	writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件，放置弹出code 127
	cmdStr := fmt.Sprintf("cd /tmp \nsudo timeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName)
	usernameNe := conf.Get("ne.user").(string) // 网元统一用户
	sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
	msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog)
	if err != nil {
		ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		return
	}

	ctx.JSON(w, 200, result.OkData(map[string]any{
		"cmd":      cmdStr,
		"msg":      msg,
		"fileName": filePcapName,
	}))
}

// TcpdumpPcapDownload 网元抓包pcap文件下载
func TcpdumpPcapDownload(w http.ResponseWriter, r *http.Request) {
	var body struct {
		NeType   string `json:"neType"`   // 网元类型
		NeId     string `json:"neId"`     // 网元ID
		FileName string `json:"fileName"` // 文件名
	}
	err := ctx.ShouldBindJSON(r, &body)
	if err != nil || body.NeType == "" || body.NeId == "" || body.FileName == "" {
		ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
		return
	}

	neInfo, err := NeInfo(body.NeType, body.NeId)
	if err != nil {
		ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		return
	}

	nePath := fmt.Sprintf("/tmp/%s", body.FileName)
	localPath := fmt.Sprintf("%s/tcpdump/pcap/%s", conf.Get("ne.omcdir"), body.FileName)
	err = ssh.FileSCPNeToLocal(neInfo.Ip, nePath, localPath)
	if err != nil {
		ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		return
	}

	ctx.FileAttachment(w, r, localPath, body.FileName)
}

// TcpdumpNeUPFTask 网元UPF发送执行 pcap
func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) {
	var body struct {
		NeType  string `json:"neType"`  // 网元类型
		NeId    string `json:"neId"`    // 网元ID
		Cmd     string `json:"cmd"`     //  命令
		RunType string `json:"runType"` // 执行开始start还是停止stop
	}
	err := ctx.ShouldBindJSON(r, &body)
	if err != nil || body.NeType != "UPF" || body.NeId == "" || body.Cmd == "" {
		ctx.JSON(w, 400, result.CodeMsg(400, "parameter error"))
		return
	}

	neInfo, err := NeInfo(body.NeType, body.NeId)
	if err != nil {
		ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		return
	}

	// 开始telnet
	if body.RunType == "start_telnet" {
		// 创建TCP连接
		conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002))
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
			return
		}
		defer conn.Close()

		filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
		cmdStr := fmt.Sprintf("pcap dispatch trace on max 100000 file %s", filePcapName)

		fmt.Fprintln(conn, cmdStr)

		// 读取内容
		time.Sleep(time.Duration(200) * time.Millisecond)
		buf := make([]byte, 1024*8)
		n, err := conn.Read(buf)
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		} else {
			str := string(buf[0:n])
			s := strings.Index(str, "pcap dispatch trace:")
			if s != -1 {
				e := strings.Index(str, "\r\nupfd1#")
				str = str[s:e]
			} else {
				str = fmt.Sprintf("Executed, please stop before proceeding %d", n)
			}
			ctx.JSON(w, 200, result.OkData(map[string]any{
				"cmd":      cmdStr,
				"msg":      str,
				"fileName": filePcapName,
			}))
		}
		conn.Close()
		return
	}
	// 停止telnet
	if body.RunType == "stop_telnet" {
		// 创建TCP连接
		conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002))
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
			return
		}
		defer conn.Close()

		filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
		cmdStr := "pcap dispatch trace off"

		fmt.Fprintln(conn, cmdStr)

		// 读取内容
		time.Sleep(time.Duration(200) * time.Millisecond)
		buf := make([]byte, 1024*8)
		n, err := conn.Read(buf)
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		} else {
			str := string(buf[0:n])
			s := strings.Index(str, "pcap dispatch trace:")
			if s == -1 {
				s = strings.Index(str, "Write ")
			}
			if s != -1 {
				e := strings.Index(str, "\r\nupfd1#")
				str = str[s:e]
			} else {
				str = "No stoppable found"
			}

			ctx.JSON(w, 200, result.OkData(map[string]any{
				"cmd":      cmdStr,
				"msg":      str,
				"fileName": filePcapName,
			}))
		}
		conn.Close()
		return
	}

	// 开始 -脚本
	if body.RunType == "start2" {
		fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
		filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
		// 复制文件到网元上
		err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp")
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
			return
		}
		writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件，放置弹出code 127
		cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace on max 100000 file %s' %s ", fileLogName, writeLog)

		usernameNe := conf.Get("ne.user").(string) // 网元统一用户
		sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
		msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		} else {
			ctx.JSON(w, 200, result.OkData(map[string]any{
				"cmd":      cmdStr,
				"msg":      msg,
				"fileName": filePcapName,
			}))
		}
		return
	}
	// 停止 -脚本
	if body.RunType == "stop2" {
		fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
		filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
		// cmdStr := "cd /tmp \nexpect /tmp/cat.sh "
		err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp")
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
			return
		}
		writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件，放置弹出code 127
		cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace off' %s ", writeLog)

		usernameNe := conf.Get("ne.user").(string) // 网元统一用户
		sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
		msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		} else {
			ctx.JSON(w, 200, result.OkData(map[string]any{
				"cmd":      cmdStr,
				"msg":      msg,
				"fileName": filePcapName,
			}))
		}
		return
	}

	// 开始-脚本字符串
	if body.RunType == "start_str" {
		fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
		filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
		scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\""
		writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出，避免弹出code 127

		capCmdStr := fmt.Sprintf("%s file %s", body.Cmd, filePcapName)

		cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog)
		usernameNe := conf.Get("ne.user").(string) // 网元统一用户
		sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
		msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		} else {
			s := strings.Index(msg, "pcap dispatch trace:")
			if s != -1 {
				e := strings.Index(msg, "\r\nupfd1#")
				msg = msg[s:e]
			} else {
				msg = "Executed, please stop before proceeding"
			}
			ctx.JSON(w, 200, result.OkData(map[string]any{
				"cmd":      capCmdStr,
				"msg":      msg,
				"fileName": filePcapName,
			}))
		}
		return
	}
	// 停止-脚本字符串
	if body.RunType == "stop_str" {
		fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
		filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
		scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\""
		writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出，避免弹出code 127

		capCmdStr := body.Cmd

		cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog)

		usernameNe := conf.Get("ne.user").(string) // 网元统一用户
		sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
		msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
		if err != nil {
			ctx.JSON(w, 200, result.ErrMsg(err.Error()))
		} else {
			s := strings.Index(msg, "pcap dispatch trace:")
			if s == -1 {
				s = strings.Index(msg, "Write ")
			}
			if s != -1 {
				e := strings.Index(msg, "\r\nupfd1#")
				msg = msg[s:e]
			} else {
				msg = "No stoppable found"
			}
			ctx.JSON(w, 200, result.OkData(map[string]any{
				"cmd":      capCmdStr,
				"msg":      msg,
				"fileName": filePcapName,
			}))
		}
		return
	}

	ctx.JSON(w, 200, result.ErrMsg("runType is start or stop"))
}
