package cm

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"be.ems/lib/dborm"
	"be.ems/lib/log"
	"be.ems/lib/services"
	"be.ems/restagent/config"

	"github.com/gorilla/mux"
)

var (
	// General License URI
	UriLicense    = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/license"
	UriLicenseExt = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/license"

	CustomUriLicense    = config.UriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/license"
	CustomUriLicenseExt = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/license"
)

func UploadLicenseFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("UploadLicenseFile 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)

	services.ResponseStatusOK204NoContent(w)
}

func DownloadLicenseFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("DownloadLicenseFile 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 DeleteLcenseFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("DeleteLcenseFile 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)
}

type MMLRequest struct {
	MML []string `json:"mml"`
}

var TIME_DELAY_AFTER_WRITE time.Duration = 200
var TIME_DEAD_LINE time.Duration = 10

func init() {
	if config.GetYamlConfig().MML.Sleep != 0 {
		TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep)
	}
	if config.GetYamlConfig().MML.DeadLine != 0 {
		TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine)
	}
}

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

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

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

	//md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false)

	neId := services.GetUriParamString(r, "neId", ",", false, false)

	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Errorf("Failed to get ne_info:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("neInfo:", neInfo)

	licensePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.License, neTypeLower)
	err = os.MkdirAll(licensePath, 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(10 << 20) // 10MB
	if err != nil {
		log.Error("Faile to ParseMultipartForm:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

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

	var licenseFileName, comment string

	// 处理license文件
	if len(licFile) > 0 {
		file := licFile[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(licensePath + "/" + file.Filename)
		if err != nil {
			log.Error("Faile to Create:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		defer dst.Close()

		licenseFileName = 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]
	}

	neLicensePath := strings.ReplaceAll(config.GetYamlConfig().NE.LicenseDir, "{neType}", neTypeLower)

	srcFile := fmt.Sprintf("%s/%s", licensePath, licenseFileName)
	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.Debugf("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
	}
	// backup system.ini to system.ini.bak
	sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
	cpCmd := fmt.Sprintf("sudo cp -f %s/system.ini %s/system.ini.bak", neLicensePath, neLicensePath)
	cmd = exec.Command("ssh", sshHost, cpCmd)
	out, err = cmd.CombinedOutput()
	log.Debugf("Exec output: %v", string(out))
	if err != nil {
		log.Error("Faile to execute cp command:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	// replace system.ini
	neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + licenseFileName
	cpCmd = fmt.Sprintf("sudo mv -f %s %s/system.ini", neFilePath, neLicensePath)
	cmd = exec.Command("ssh", sshHost, cpCmd)
	out, err = cmd.CombinedOutput()
	log.Debugf("Exec output: %v", string(out))
	if err != nil {
		log.Error("Faile to execute cp command:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	/*
		// judge license if expired
		isRestart := false
		hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
		requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
			hostUri, neTypeLower)
		log.Debug("requestURI2NF:", requestURI2NF)

		resp, err := client.R().
			EnableTrace().
			SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}).
			//SetHeaders(map[string]string{"accessToken": token}).
			SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
			SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
			Get(requestURI2NF)
		if err != nil {
			log.Error("Failed to get system state:", err)
			isRestart = true
		} else {
			systemState := make(map[string]interface{})
			_ = json.Unmarshal(resp.Body(), &systemState)
			expiryDate := fmt.Sprintf("%v", systemState["expiryDate"])
			t1_expiry, _ := time.ParseInLocation(time.DateOnly, expiryDate, time.Local)
			nowDate := time.Now().Local()
			nowDate.Format(time.DateOnly)
			isRestart = t1_expiry.Before(nowDate)
		}
		// case non-expired license: send NE reload license MML
		if !isRestart {
			// send reload license MML
			var buf [20 * 1024]byte
			//buf := make([]byte, 0)
			var n int
			if neInfo != nil {
				switch strings.ToLower(neType) {
				case "ims":
					hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port)
					conn, err := net.Dial("tcp", hostMML)
					if err != nil {
						errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err)
						log.Error(errMsg)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					defer conn.Close()

					conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second))

					_, err = conn.Write([]byte(config.GetYamlConfig().MML.User + "\r\n"))
					if err != nil {
						log.Error("Failed to write:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

					n, err = conn.Read(buf[0:])
					if err != nil {
						log.Error("Failed to read:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					log.Trace(string(buf[0:n]))

					_, err = conn.Write([]byte(config.GetYamlConfig().MML.Password + "\r\n"))
					if err != nil {
						log.Error("Failed to write:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

					n, err = conn.Read(buf[0:])
					if err != nil {
						log.Error("Failed to read:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					log.Trace(string(buf[0 : n-len(neType)-2]))

					mmlCommand := "check lic\r\n"

					_, err = conn.Write([]byte(mmlCommand))
					if err != nil {
						log.Error("Failed to write:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

					n, err = conn.Read(buf[0:])
					if err != nil {
						log.Error("Failed to read:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					log.Trace(string(buf[0 : n-len(neType)-2]))

					re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符
					//re2 := regexp.MustCompile(`\x00`) // 匹配空字符
					re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符
					//re := regexp.MustCompile(`[\x00-\x1F\x7F]`)
					// upf telnet buffer只能读取一次，需要去掉前面的多余字符
					result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "")
					result = re2.ReplaceAllString(result, "")
					if !strings.Contains(result, "COMMAND OK") {
						err = fmt.Errorf("failed to check license, %s", result)
						log.Error(err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
				default:
					hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port)
					conn, err := net.Dial("tcp", hostMML)
					if err != nil {
						errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err)
						log.Error(errMsg)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					defer conn.Close()

					conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second))
					loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password)
					_, err = conn.Write([]byte(loginStr))
					if err != nil {
						log.Error("Failed to write:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}

					time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

					n, err = conn.Read(buf[0:])
					if err != nil {
						log.Error("Failed to read:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					log.Trace(string(buf[0:n]))

					mmlCommand := "check lic\n"
					_, err = conn.Write([]byte(mmlCommand))
					if err != nil {
						log.Error("Failed to write:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

					n, err = conn.Read(buf[0:])
					if err != nil {
						log.Error("Failed to read:", err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
					log.Trace(string(buf[0 : n-len(neType)-2]))
					re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符
					//re2 := regexp.MustCompile(`\x00`) // 匹配空字符
					re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符
					//re := regexp.MustCompile(`[\x00-\x1F\x7F]`)
					result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "")
					result = re2.ReplaceAllString(result, "")
					if !strings.Contains(result, "COMMAND OK") {
						err = fmt.Errorf("failed to check license, %s", result)
						log.Error(err)
						services.ResponseInternalServerError500ProcessError(w, err)
						return
					}
				}
			}
		} else {
			// case expired license: restart NE service
			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.Debugf("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.Debugf("Exec output: %v", string(out))
				if err != nil {
					log.Error("Faile to execute ssh sudo systemctl command:", 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.Debugf("Exec output: %v", string(out))
				if err != nil {
					log.Error("Faile to execute ssh sudo systemctl command:", err)
					services.ResponseInternalServerError500ProcessError(w, err)
					return
				}
			}
		}
	*/
	neLicense := dborm.NeLicense{
		NeType:   neTypeUpper,
		NeID:     neId,
		Status:   "ACTIVE",
		Path:     licensePath,
		FileName: licenseFileName,
		Comment:  comment,
	}

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

	services.ResponseStatusOK204NoContent(w)
}
