package cm

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"nms_nbi/lib/dborm"
	"nms_nbi/lib/global"
	"nms_nbi/lib/log"
	"nms_nbi/lib/services"
	"nms_nbi/restagent/config"

	"github.com/gorilla/mux"
)

const (
	SoftwareStatusUploaded = "Uploaded"
	SoftwareStatusInactive = "Inactive"
	SoftwareStatusActive   = "Active"
	DigestsSignOkString    = "digests signatures OK"
	SoftwareVerifiedOk     = "Verified OK"
)

var (
	UriSoftware   = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}"
	UriSoftwareNE = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}"

	CustomUriSoftware   = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}"
	CustomUriSoftwareNE = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}"
)

// 验证签名
func verify_signature(public_key_name string, source_cms_file string, source_file string) bytes.Buffer {
	cmd := exec.Command("/usr/local/omc/run/iv", "verify_signature", public_key_name, source_cms_file, source_file)
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Env = append(os.Environ(),
		"FOO=duplicate_value", // 重复被忽略
		"FOO=actual_value",    // 实际被使用
	)
	err := cmd.Run()
	if err != nil {
		log.Error(err)
	}

	return out
}

func UploadSoftwareFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("UploadSoftwareFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Http request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false)

	// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	// if err != nil {
	// 	log.Error("io.ReadAll is failed:", err)
	// 	services.ResponseNotFound404UriNotExist(w, r)
	// 	return
	// }
	// neSWBody := new(dborm.NeSoftware)
	// _ = json.Unmarshal(body, neSWBody)
	// log.Trace("neSoftware:", neSWBody)

	softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower)
	fileName, err := services.HandleUploadFile(r, softwarePath, "")
	if err != nil {
		log.Error("Faile to HandleUploadFile:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	filePrefix := fileName[:strings.Index(fileName, ".zip")]
	filePath := fmt.Sprintf("%s/%s", softwarePath, fileName)
	log.Debugf("filePath:%s filePrefix:%s softwarePath:%s", filePath, filePrefix, softwarePath)
	cmd := exec.Command("unzip", "-o", filePath)
	cmd.Dir = softwarePath
	out, err := cmd.CombinedOutput()
	log.Debugf("Exec outpout:%s", string(out))
	if err != nil {
		log.Error("Failed to unzip:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	md5File, err := global.GetFileMD5Sum(filePath)
	if err != nil {
		log.Error("Faile to GetFileMD5Sum:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	if md5File != md5Param {
		err = global.ErrCMNotMatchMD5File
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	rpmFileName := filePrefix + ".rpm"
	if config.GetYamlConfig().OMC.CheckSign {
		rpmFilePath := softwarePath + "/" + rpmFileName
		cmsFileName := rpmFileName + ".cms"
		cmsFilePath := softwarePath + "/" + cmsFileName
		log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey)
		result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath)
		log.Debug("result:", result.String())
		if !strings.Contains(result.String(), SoftwareVerifiedOk) {
			err = global.ErrCMNotMatchSignFile
			log.Error(err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		// cmd := exec.Command("rpm", "-K", filePath)
		// out, err := cmd.CombinedOutput()
		// log.Debugf("Exec outpout:%s", string(out))
		// if err != nil {
		// 	log.Error("Failed to execute rpm:", err)
		// 	services.ResponseInternalServerError500ProcessError(w, err)
		// 	return
		// }
		// if !strings.Contains(string(out), DigestsSignOkString) {
		// 	err = global.ErrCMNotMatchSignFile
		// 	log.Error(err)
		// 	services.ResponseInternalServerError500ProcessError(w, err)
		// 	return
		// }
	}

	//neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
	//log.Debug("neBackup:", neBackup)
	where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
	has, err := dborm.XormExistTableOne("ne_software", where)
	if err != nil {
		log.Error("Faile to XormInsertTableOne:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if has {
		err = global.ErrCMExistSoftwareFile
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	neSoftware := dborm.NeSoftware{
		NeType:   neTypeUpper,
		FileName: rpmFileName,
		Path:     softwarePath,
		Version:  version,
		Md5Sum:   md5Param,
		Comment:  neType + " 5GC " + version,
		//Comment: neSWBody.Comment,
	}

	_, err = dborm.XormInsertTableOne("ne_software", neSoftware)
	if err != nil {
		log.Error("Faile to XormInsertTableOne:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}

func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) {
	log.Info("UploadSoftwareMultiFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Http request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false)

	softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower)
	err = os.MkdirAll(softwarePath, os.ModePerm)
	if err != nil {
		log.Error("Failed to Mkdir:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	//fileName, err := services.HandleUploadFile(r, softwarePath, "")

	// 解析multipart/form-data请求
	err = r.ParseMultipartForm(1000 << 20) // 1000MB
	if err != nil {
		log.Error("Faile to ParseMultipartForm:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	// 获取文件和数据
	swFile := r.MultipartForm.File["file"]
	cmsFile := r.MultipartForm.File["cms"]
	data := r.MultipartForm.Value["comment"]

	var softwareFileName, cmsFileName, comment string

	// 处理软件rpm/deb文件
	if len(swFile) > 0 {
		file := swFile[0]
		// 打开文件
		f, err := file.Open()
		if err != nil {
			log.Error("Faile to Open:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		defer f.Close()

		// 创建本地文件
		dst, err := os.Create(softwarePath + "/" + file.Filename)
		if err != nil {
			log.Error("Faile to Create:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		defer dst.Close()

		softwareFileName = file.Filename
		// 将文件内容拷贝到本地文件
		_, err = io.Copy(dst, f)
		if err != nil {
			log.Error("Faile to Copy:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	}

	// 处理cms文件
	if len(cmsFile) > 0 {
		file := cmsFile[0]
		// 打开文件
		f, err := file.Open()
		if err != nil {
			log.Error("Faile to Open:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		defer f.Close()

		// 创建本地文件
		dst, err := os.Create(softwarePath + "/" + file.Filename)
		if err != nil {
			log.Error("Faile to Create:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		defer dst.Close()

		cmsFileName = file.Filename
		// 将文件内容拷贝到本地文件
		_, err = io.Copy(dst, f)
		if err != nil {
			log.Error("Faile to Copy:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	}

	// 处理数据
	if len(data) > 0 {
		comment = data[0]
	}

	if config.GetYamlConfig().OMC.CheckSign && cmsFileName != "" {
		rpmFilePath := softwarePath + "/" + softwareFileName
		cmsFileName := cmsFileName
		cmsFilePath := softwarePath + "/" + cmsFileName
		log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey)
		result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath)
		log.Debug("result:", result.String())
		if !strings.Contains(result.String(), SoftwareVerifiedOk) {
			err = global.ErrCMNotMatchSignFile
			log.Error(err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		// cmd := exec.Command("rpm", "-K", filePath)
		// out, err := cmd.CombinedOutput()
		// log.Debugf("Exec outpout:%s", string(out))
		// if err != nil {
		// 	log.Error("Failed to execute rpm:", err)
		// 	services.ResponseInternalServerError500ProcessError(w, err)
		// 	return
		// }
		// if !strings.Contains(string(out), DigestsSignOkString) {
		// 	err = global.ErrCMNotMatchSignFile
		// 	log.Error(err)
		// 	services.ResponseInternalServerError500ProcessError(w, err)
		// 	return
		// }
	}

	// //neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
	// //log.Debug("neBackup:", neBackup)
	// where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
	// has, err := dborm.XormExistTableOne("ne_software", where)
	// if err != nil {
	// 	log.Error("Faile to XormInsertTableOne:", err)
	// 	services.ResponseInternalServerError500ProcessError(w, err)
	// 	return
	// } else if has == true {
	// 	err = global.ErrCMExistSoftwareFile
	// 	log.Error(err)
	// 	services.ResponseInternalServerError500ProcessError(w, err)
	// 	return
	// }

	neSoftware := dborm.NeSoftware{
		NeType:   neTypeUpper,
		FileName: softwareFileName,
		Path:     softwarePath,
		Version:  version,
		Md5Sum:   md5Param,
		Comment:  comment,
	}

	_, err = dborm.XormInsertTableOne("ne_software", neSoftware)
	if err != nil {
		log.Error("Faile to XormInsertTableOne:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}

func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("DownloadSoftwareFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	//neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
	neSoftware, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neSoftware) == 0 {
		err := global.ErrCMNotFoundTargetSoftware
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	fileName := (*neSoftware)[0]["file_name"]
	path := (*neSoftware)[0]["path"]
	md5Sum := (*neSoftware)[0]["md5_sum"]

	services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
}

func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("DeleteSoftwareFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	//neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
	neSoftware, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neSoftware) == 0 {
		err := global.ErrCMNotFoundTargetSoftware
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
	affected, err := dborm.XormDeleteDataByWhere(where, "ne_software")
	if err != nil || affected == 0 {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	fileName := (*neSoftware)[0]["file_name"]
	path := (*neSoftware)[0]["path"]
	filePath := fmt.Sprintf("%s/%s", path, fileName)
	err = os.Remove(filePath)
	if err != nil {
		log.Error("Faile to Remove:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}

func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) {
	log.Debug("DistributeSoftwareFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Http request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neId := vars["neId"]
	if version == "" {
		log.Error("neId is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}

	sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
	neSoftware, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neSoftware) == 0 {
		err := global.ErrCMNotFoundTargetSoftware
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neSoftware:", neSoftware)

	sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId)
	neVersion, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neVersion:", neVersion)

	sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
	mkdirCmd := fmt.Sprintf("sudo mkdir -p %s/software/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower)
	cmd := exec.Command("ssh", sshHost, mkdirCmd)
	out, err := cmd.CombinedOutput()
	log.Tracef("Exec output: %v", string(out))
	if err != nil {
		log.Error("Faile to mkdir:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	fileName := (*neSoftware)[0]["file_name"]
	path := (*neSoftware)[0]["path"]
	srcFile := fmt.Sprintf("%s/%s", path, fileName)

	scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
		neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
	cmd = exec.Command("scp", "-r", srcFile, scpDir)
	out, err = cmd.CombinedOutput()
	log.Tracef("Exec output: %v", string(out))
	if err != nil {
		log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + fileName
	cpCmd := fmt.Sprintf("sudo mv -f %s %s/software/%s", neFilePath,
		config.GetYamlConfig().NE.OmcDir, neTypeLower)
	cmd = exec.Command("ssh", sshHost, cpCmd)
	out, err = cmd.CombinedOutput()
	log.Tracef("Exec output: %v", string(out))
	if err != nil {
		log.Error("Faile to execute cp command:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	if len(*neVersion) == 0 {
		neVersionData := dborm.NeVersion{
			NeType:     neTypeUpper,
			NeId:       neInfo.NeId,
			Version:    (*neSoftware)[0]["version"],
			FilePath:   fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
			PreVersion: "",
			PreFile:    "",
			Status:     SoftwareStatusInactive,
		}

		_, err = dborm.XormInsertTableOne("ne_version", neVersionData)
		if err != nil {
			log.Error("Faile to XormInsertTableOne:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	} else {
		idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
		neVersionData := dborm.NeVersion{
			NeType:     neTypeUpper,
			NeId:       neInfo.NeId,
			Version:    (*neSoftware)[0]["version"],
			FilePath:   fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
			PreVersion: (*neVersion)[0]["version"],
			PreFile:    (*neVersion)[0]["file_path"],
			Status:     SoftwareStatusInactive,
		}

		_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
		if err != nil {
			log.Error("Faile to UpdateTableById:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	}

	services.ResponseStatusOK204NoContent(w)
}

func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) {
	log.Debug("ActiveSoftwareToNF processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Http request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neId := vars["neId"]
	if version == "" {
		log.Error("neId is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}

	sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
	neSoftware, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neSoftware) == 0 {
		err := global.ErrCMNotFoundTargetSoftware
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neSoftware:", neSoftware)

	sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s' and version='%s'", neTypeUpper, neId, version)
	neVersion, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neVersion) == 0 {
		err := global.ErrCMNotFoundTargetNeVersion
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neVersion:", neVersion)

	if !config.GetYamlConfig().OMC.TestMode {
		filePath := (*neVersion)[0]["file_path"]
		sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
		srcFile := fmt.Sprintf("%s/actpkg.sh", config.GetYamlConfig().OMC.BinDir)

		scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
			neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
		cmd := exec.Command("scp", "-r", srcFile, scpDir)
		_, err := cmd.CombinedOutput()
		if err != nil {
			log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}

		runCmd := fmt.Sprintf("sudo %s/actpkg.sh '%s' %s",
			config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper)
		if neTypeLower == "omc" {
			idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
			neVersionData := dborm.NeVersion{
				Status: SoftwareStatusActive,
			}

			_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
			if err != nil {
				log.Error("Faile to UpdateTableById:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}

			services.ResponseStatusOK204NoContent(w)
			go RunSSHCmd(sshHost, runCmd)
			return
		}
		err = RunSSHCmd(sshHost, runCmd)
		if err != nil {
			log.Errorf("Faile to execute command: %s, error: %v", runCmd, err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}

		// fileType := global.IsRpmOrDebPackage(filePath)
		// if fileType == 1 {
		// 	srcFile := fmt.Sprintf("%s/spawnrpm.sh", config.GetYamlConfig().OMC.BinDir)

		// 	scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
		// 		neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
		// 	cmd := exec.Command("scp", "-r", srcFile, scpDir)
		// 	_, err := cmd.CombinedOutput()
		// 	if err != nil {
		// 		log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}

		// 	dpkgCmd := fmt.Sprintf("sudo %s/spawnrpm.sh '%s'",
		// 		config.GetYamlConfig().NE.ScpDir, filePath)
		// 	err = RunSSHCmd(sshHost, dpkgCmd)
		// 	if err != nil {
		// 		log.Errorf("Faile to execute dpkg command: %s, error: %v", dpkgCmd, err)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}
		// } else if fileType == 2 {
		// 	srcFile := fmt.Sprintf("%s/spawndpkg.sh", config.GetYamlConfig().OMC.BinDir)

		// 	scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
		// 		neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
		// 	cmd := exec.Command("scp", "-r", srcFile, scpDir)
		// 	_, err := cmd.CombinedOutput()
		// 	if err != nil {
		// 		log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}

		// 	dpkgCmd := fmt.Sprintf("sudo %s/spawndpkg.sh '%s'",
		// 		config.GetYamlConfig().NE.ScpDir, filePath)
		// 	err = RunSSHCmd(sshHost, dpkgCmd)
		// 	if err != nil {
		// 		log.Errorf("Faile to execute dpkg command: %s, error: %v", dpkgCmd, err)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}
		// } else {
		// 	err := global.ErrCMUnknownSoftwareFormat
		// 	log.Error(err)
		// 	services.ResponseInternalServerError500ProcessError(w, err)
		// 	return
		// }
		switch neTypeLower {
		case "omc":
			restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir)
			cmd := exec.Command("ssh", sshHost, restartCmd)
			out, err := cmd.CombinedOutput()
			log.Tracef("Exec output: %v", string(out))
			if err != nil {
				log.Error("Faile to execute ssh restart omc:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		case "ims":
			restartCmd := "sudo ims-stop && sudo ims-start"
			cmd := exec.Command("ssh", sshHost, restartCmd)
			out, err := cmd.CombinedOutput()
			log.Tracef("Exec output: %v", string(out))
			if err != nil {
				log.Error("Faile to execute ssh command: %s, error: %v", restartCmd, err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		default:
			restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower)
			cmd := exec.Command("ssh", sshHost, restartCmd)
			out, err := cmd.CombinedOutput()
			log.Tracef("Exec output: %v", string(out))
			if err != nil {
				log.Error("Faile to execute ssh sudo systemctl command:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		}
	}

	idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
	neVersionData := dborm.NeVersion{
		Status: SoftwareStatusActive,
	}

	_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
	if err != nil {
		log.Error("Faile to UpdateTableById:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}

func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
	log.Debug("ActiveSoftwareToNF processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Http request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	version := vars["version"]
	if version == "" {
		log.Error("version is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neId := vars["neId"]
	if version == "" {
		log.Error("neId is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}

	sql := fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId)
	neVersion, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neVersion) == 0 {
		err := global.ErrCMNotFoundTargetNeVersion
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("neVersion:", neVersion)

	filePath := (*neVersion)[0]["pre_file"]
	if filePath == "" {
		err := global.ErrCMNotFoundRollbackNeVersion
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	if !config.GetYamlConfig().OMC.TestMode {
		sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
		srcFile := fmt.Sprintf("%s/rbkpkg.sh", config.GetYamlConfig().OMC.BinDir)

		scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
			neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
		cmd := exec.Command("scp", "-r", srcFile, scpDir)
		_, err := cmd.CombinedOutput()
		if err != nil {
			log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}

		runCmd := fmt.Sprintf("sudo %s/rbkpkg.sh '%s' %s",
			config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper)
		if neTypeLower == "omc" {
			idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
			neVersionData := dborm.NeVersion{
				Version:    (*neVersion)[0]["pre_version"],
				FilePath:   (*neVersion)[0]["pre_file"],
				PreVersion: "-",
				PreFile:    "-",
				NewVersion: (*neVersion)[0]["version"],
				NewFile:    (*neVersion)[0]["file_path"],
				Status:     SoftwareStatusActive,
			}

			_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
			if err != nil {
				log.Error("Faile to UpdateTableById:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
			services.ResponseStatusOK204NoContent(w)
			RunSSHCmd(sshHost, runCmd)
			return
		}
		err = RunSSHCmd(sshHost, runCmd)
		if err != nil {
			log.Errorf("Faile to execute command: %s, error: %v", runCmd, err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		// fileType := global.IsRpmOrDebPackage(filePath)
		// if fileType == 1 {
		// 	rpmCmd := fmt.Sprintf("sudo rpm -Uvh --oldpackage '%s'", filePath)
		// 	cmd := exec.Command("ssh", sshHost, rpmCmd)
		// 	_, err := cmd.CombinedOutput()
		// 	if err != nil {
		// 		log.Error("Faile to execute rpm command:", err)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}
		// } else if fileType == 2 {
		// 	srcFile := fmt.Sprintf("%s/spawndpkg.sh", config.GetYamlConfig().OMC.BinDir)

		// 	scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
		// 		neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
		// 	cmd := exec.Command("scp", "-r", srcFile, scpDir)
		// 	_, err := cmd.CombinedOutput()
		// 	if err != nil {
		// 		log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}
		// 	var inputStr string = "n"
		// 	if config.GetYamlConfig().NE.DpkgOverwrite {
		// 		inputStr = "y"
		// 	}
		// 	dpkgCmd := fmt.Sprintf("sudo %s/spawndpkg.sh %s '%s'",
		// 		config.GetYamlConfig().NE.ScpDir, inputStr, filePath)
		// 	err = RunSSHCmd(sshHost, dpkgCmd)
		// 	if err != nil {
		// 		log.Errorf("Faile to execute dpkg command: %s, error: %v", dpkgCmd, err)
		// 		services.ResponseInternalServerError500ProcessError(w, err)
		// 		return
		// 	}
		// } else {
		// 	err := global.ErrCMUnknownSoftwareFormat
		// 	log.Error(err)
		// 	services.ResponseInternalServerError500ProcessError(w, err)
		// 	return
		// }
		switch neTypeLower {
		case "omc":
			restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir)
			cmd := exec.Command("ssh", sshHost, restartCmd)
			out, err := cmd.CombinedOutput()
			log.Tracef("Exec output: %v", string(out))
			if err != nil {
				log.Error("Faile to execute ssh restart omc:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		case "ims":
			restartCmd := "sudo ims-stop && sudo ims-start"
			cmd := exec.Command("ssh", sshHost, restartCmd)
			out, err := cmd.CombinedOutput()
			log.Tracef("Exec output: %v", string(out))
			if err != nil {
				log.Error("Faile to execute ssh command: %s, error: %v", restartCmd, err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		default:
			restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower)
			cmd := exec.Command("ssh", sshHost, restartCmd)
			out, err := cmd.CombinedOutput()
			log.Tracef("Exec output: %v", string(out))
			if err != nil {
				log.Error("Faile to execute ssh sudo systemctl command:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}

		}
	}

	idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
	neVersionData := dborm.NeVersion{
		Version:    (*neVersion)[0]["pre_version"],
		FilePath:   (*neVersion)[0]["pre_file"],
		PreVersion: "-",
		PreFile:    "-",
		NewVersion: (*neVersion)[0]["version"],
		NewFile:    (*neVersion)[0]["file_path"],
		Status:     SoftwareStatusActive,
	}

	_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
	if err != nil {
		log.Error("Faile to UpdateTableById:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}
