package controller

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/gin-gonic/gin"

	"be.ems/src/framework/cmd"
	"be.ems/src/framework/i18n"
	"be.ems/src/framework/reqctx"
	"be.ems/src/framework/resp"
	"be.ems/src/framework/utils/file"
	"be.ems/src/framework/utils/generate"
	neService "be.ems/src/modules/ne/service"
)

// 实例化控制层 NeActionController 结构体
var NewNeAction = &NeActionController{
	neInfoService: neService.NewNeInfo,
}

// 网元处理请求
//
// PATH /action
type NeActionController struct {
	// 网元信息服务
	neInfoService *neService.NeInfo
}

// 从本地到网元发送文件
//
// POST /pushFile
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			data	body		object	true	"Request Param"
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Sending files from local to network elements
//	@Description	Sending files from local to network elements
//	@Router			/ne/action/pushFile [post]
func (s *NeActionController) PushFile(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var body struct {
		NeType     string `json:"neType" binding:"required"`
		NeID       string `json:"neId" binding:"required"`
		UploadPath string `json:"uploadPath" binding:"required"`
		DelTemp    bool   `json:"delTemp"` // 删除本地临时文件
	}
	if err := c.ShouldBindBodyWithJSON(&body); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询网元获取IP
	neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeID)
	if neInfo.NeId != body.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}

	// 网元主机的SSH客户端
	// sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sshClient.Close()
	// // 网元主机的SSH客户端进行文件传输
	// sftpClient, err := sshClient.NewClientSFTP()
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sftpClient.Close()

	// 本地文件
	localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
	// 网元端临时目录
	// sshClient.RunCMD("mkdir -p /tmp/omc/push && sudo chmod 777 -R /tmp/omc")
	cmd.Exec("sudo mkdir -p /tmp/omc/push && sudo chmod 777 -R /tmp/omc")
	neFilePath := filepath.ToSlash(filepath.Join("/tmp/omc/push", filepath.Base(localFilePath)))
	// 复制到远程
	// if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
	// 	c.JSON(200, resp.ErrMsg("Please check if the file exists or if scp is allowed to copy remotely"))
	// 	return
	// }
	if err := file.CopyFile(localFilePath, neFilePath); err != nil {
		c.JSON(200, resp.ErrMsg("Please check if the file exists or if scp is allowed to copy remotely"))
		return
	}

	defer func() {
		if body.DelTemp {
			_ = os.Remove(localFilePath)
		}
	}()
	c.JSON(200, resp.OkData(filepath.ToSlash(neFilePath)))
}

// 从网元到本地获取文件
//
// GET /pullFile
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType		query		string	true	"NE Type"	Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)	default(UPF)
//	@Param			neId		query		string	true	"NE ID"		default(001)
//	@Param			path		query		string	true	"dir path"	default(/var/log)
//	@Param			fileName	query		string	true	"file name"
//	@Param			delTemp		query		boolean	false	"Delete Temp File"	default(false)
//	@Success		200			{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Getting files from the network element to the local
//	@Description	Getting files from the network element to the local
//	@Router			/ne/action/pullFile [get]
func (s *NeActionController) PullFile(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var querys struct {
		NeType   string `form:"neType" binding:"required"`
		NeID     string `form:"neId" binding:"required"`
		Path     string `form:"path" binding:"required"`
		FileName string `form:"fileName" binding:"required"`
		DelTemp  bool   `form:"delTemp"` // 删除本地临时文件
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询网元获取IP
	neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID)
	if neInfo.NeId != querys.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}

	// 网元主机的SSH客户端
	// sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sshClient.Close()
	// // 网元主机的SSH客户端进行文件传输
	// sftpClient, err := sshClient.NewClientSFTP()
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sftpClient.Close()

	nePath := filepath.ToSlash(filepath.Join(querys.Path, querys.FileName))
	fileName := generate.Code(6) + "_" + querys.FileName
	localFilePath := filepath.Join("/tmp/omc/pull", fileName)
	if runtime.GOOS == "windows" {
		localFilePath = fmt.Sprintf("C:%s", localFilePath)
	}
	// 复制到本地
	// if err = sftpClient.CopyFileRemoteToLocal(nePath, localFilePath); err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	if err := file.CopyFile(nePath, localFilePath); err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}

	defer func() {
		if querys.DelTemp {
			_ = os.Remove(localFilePath)
		}
	}()
	c.FileAttachment(localFilePath, fileName)
}

// 从网元到本地获取目录压缩为ZIP
//
// GET /pullDirZip
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType	query		string	true	"NE Type"			Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)	default(UPF)
//	@Param			neId	query		string	true	"NE ID"				default(001)
//	@Param			path	query		string	true	"dir path"			default(/var/log)
//	@Param			delTemp	query		boolean	false	"Delete Temp File"	default(false)
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Get directories compressed to ZIP from the network element to the local area
//	@Description	Get directories compressed to ZIP from the network element to the local area
//	@Router			/ne/action/pullDirZip [get]
func (s *NeActionController) PullDirZip(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var querys struct {
		NeType  string `form:"neType" binding:"required"`
		NeID    string `form:"neId" binding:"required"`
		Path    string `form:"path" binding:"required"`
		DelTemp bool   `form:"delTemp"` // 删除本地临时文件
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询网元获取IP
	neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID)
	if neInfo.NeId != querys.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}

	// 网元主机的SSH客户端
	// sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sshClient.Close()
	// // 网元主机的SSH客户端进行文件传输
	// sftpClient, err := sshClient.NewClientSFTP()
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sftpClient.Close()

	nePath := querys.Path
	dirName := generate.Code(6)
	localFilePath := filepath.Join("/tmp/omc/pull/", dirName)
	if runtime.GOOS == "windows" {
		localFilePath = fmt.Sprintf("C:%s", localFilePath)
	}
	// 复制到本地
	localDirFilePath := filepath.Join(localFilePath, "zip")
	// if err = sftpClient.CopyDirRemoteToLocal(nePath, localDirFilePath); err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	if err := file.CopyDir(nePath, localDirFilePath); err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}

	// 压缩zip文件名
	zipFileName := fmt.Sprintf("%s-%s-%s.zip", neInfo.NeType, neInfo.NeId, dirName)
	zipFilePath := filepath.Join(localFilePath, zipFileName)
	if err := file.CompressZipByDir(zipFilePath, localDirFilePath); err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}

	defer func() {
		if querys.DelTemp {
			_ = os.RemoveAll(localFilePath)
		}
	}()
	c.FileAttachment(zipFilePath, zipFileName)
}

// 查看网元端文件内容
//
// GET /viewFile
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType		query		string	true	"NE Type"	Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)	default(UPF)
//	@Param			neId		query		string	true	"NE ID"		default(001)
//	@Param			path		query		string	true	"file path"	default(/var/log)
//	@Param			fileName	query		string	true	"file name"
//	@Success		200			{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Viewing the contents of a file on the network element side
//	@Description	Viewing the contents of a file on the network element side
//	@Router			/ne/action/viewFile [get]
func (s *NeActionController) ViewFile(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var querys struct {
		NeType   string `form:"neType" binding:"required"`
		NeID     string `form:"neId" binding:"required"`
		Path     string `form:"path" binding:"required"`
		FileName string `form:"fileName" binding:"required"`
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询网元获取IP
	neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID)
	if neInfo.NeId != querys.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}

	// 网元主机的SSH客户端
	// sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sshClient.Close()

	// 网元端文件
	nePath := filepath.ToSlash(filepath.Join(querys.Path, querys.FileName))
	// 网元端临时目录
	output, err := cmd.Execf("cat %s", nePath)
	output = strings.TrimSpace(output)
	if err != nil || strings.HasPrefix(output, "ls: ") {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "file view cat error")))
		return
	}
	c.JSON(200, resp.OkData(output))
}

// 网元端文件列表
//
// GET /files
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			neType		query		string	true	"NE Type"		Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)	default(UPF)
//	@Param			neId		query		string	true	"NE ID"			default(001)
//	@Param			path		query		string	true	"file path"		default(/var/log)
//	@Param			pageNum		query		number	true	"pageNum"		default(1)
//	@Param			pageSize	query		number	true	"pageSize"		default(10)
//	@Param			search		query		string	false	"search prefix"	default(upf)
//	@Success		200			{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		List of files on the network element side
//	@Description	List of files on the network element side
//	@Router			/ne/action/files [get]
func (s *NeActionController) Files(c *gin.Context) {
	var querys struct {
		NeType   string `form:"neType" binding:"required"`
		NeID     string `form:"neId" binding:"required"`
		Path     string `form:"path"  binding:"required"`
		PageNum  int64  `form:"pageNum"  binding:"required"`
		PageSize int64  `form:"pageSize"  binding:"required"`
		Search   string `form:"search"`
	}
	if err := c.ShouldBindQuery(&querys); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// // 查询网元获取IP
	// neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID)
	// if neInfo.NeId != querys.NeID || neInfo.IP == "" {
	// 	c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
	// 	return
	// }

	// // 网元主机的SSH客户端
	// sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
	// if err != nil {
	// 	c.JSON(200, resp.ErrMsg(err.Error()))
	// 	return
	// }
	// defer sshClient.Close()

	// 获取文件列表
	rows, err := file.FileList(querys.Path, querys.Search)
	if err != nil {
		c.JSON(200, resp.OkData(map[string]any{
			"path":  querys.Path,
			"total": len(rows),
			"rows":  []file.FileListRow{},
		}))
		return
	}

	// 对数组进行切片分页
	lenNum := int64(len(rows))
	start := (querys.PageNum - 1) * querys.PageSize
	end := start + querys.PageSize
	var splitRows []file.FileListRow
	if start >= lenNum {
		splitRows = []file.FileListRow{}
	} else if end >= lenNum {
		splitRows = rows[start:]
	} else {
		splitRows = rows[start:end]
	}

	c.JSON(200, resp.OkData(map[string]any{
		"path":  querys.Path,
		"total": lenNum,
		"rows":  splitRows,
	}))
}

// 网元服务操作
//
// PUT /service
//
//	@Tags			ne
//	@Accept			json
//	@Produce		json
//	@Param			data	body		object	true	"Request Param"
//	@Success		200		{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Network element service operation
//	@Description	Network element service operation
//	@Router			/ne/action/service [put]
func (s *NeActionController) Service(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	var body struct {
		NeType string `json:"neType" binding:"required"`
		NeID   string `json:"neId" binding:"required"`
		Action string `json:"action" binding:"required,oneof=start restart stop reboot poweroff"` // 操作行为
	}
	if err := c.ShouldBindBodyWithJSON(&body); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	// 查询网元获取IP
	neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeID)
	if neInfo.NeId != body.NeID || neInfo.IP == "" {
		c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
		return
	}

	neTypeLower := strings.ToLower(neInfo.NeType)
	cmdStr := fmt.Sprintf("sudo systemctl %s %s", body.Action, neTypeLower)
	switch neTypeLower {
	case "omc":
		cmdStr = fmt.Sprintf("nohup sh -c \"sudo systemctl stop omc && sleep 5s && sudo systemctl %s omc\" > /dev/null 2>&1 &", body.Action)
	case "ims":
		if body.Action == "restart" {
			cmdStr = "ims-stop || true && ims-start"
		} else {
			cmdStr = fmt.Sprintf("sudo ims-%s", body.Action)
		}
	}

	if body.Action == "reboot" {
		cmdStr = "sudo shutdown -r now"
	}
	if body.Action == "poweroff" {
		cmdStr = "sudo shutdown -h now"
	}

	_, err := s.neInfoService.NeRunSSHCmd(body.NeType, body.NeID, cmdStr)
	if err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.Ok(nil))
}
