package services

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"os"
	"path/filepath"

	//	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"be.ems/lib/dborm"
	"be.ems/lib/global"
	"be.ems/lib/log"
	"be.ems/lib/oauth"
	"be.ems/restagent/config"
	"github.com/gorilla/mux"
)

type NameValue struct {
	Name  string
	Value string
}

type NameOid struct {
	Name string
	Oid  string
}

type DataResponse struct {
	Data interface{} `json:"data"`
}

type MapResponse map[string]any

type NullResponse struct {
	nil interface{}
}

type ErrorResponse struct {
	Error interface{} `json:"error"`
}

type ErrorMessage struct {
	ErrorCode string `json:"errorCode"`
	ErrorInfo string `json:"errorInfo"`
}

type SucceedOAuthResponse struct {
	AccessToken string `json:"accessToken"`
	Expires     string `json:"expires"`
	// Enum: "0": 不需要修改密码, "1": "FirstLogin",首次登录, "2": PasswordAboutToExpire, 密码即将过期
	ChangePasswordFlag int      `json:"changePasswordFlag"`
	GroupName          string   `json:"groupName"`
	Roles              []string `json:"roles"`
	Perms              []string `json:"perms"`
}

type ServiceResponse struct {
}

func GetUriParamString(r *http.Request, paramName string, sep string, brackets bool, apostr bool) string {
	vars := r.URL.Query()
	s, ok := vars[paramName]
	if !ok {
		log.Infof("Parameter Name is not exist, %s", paramName)
		return ""
	}
	if apostr {
		for i := 0; i < len(s); i++ {
			s[i] = "'" + s[i] + "'"
		}
	}
	pn := strings.Join(s, sep)
	if brackets {
		pn = fmt.Sprintf("(%s)", pn)
	}

	return pn
}

func GetUriWhereString(r *http.Request) string {
	return GetUriParamString(r, "WHERE", " and ", false, false)
}

func GetUriLocString(r *http.Request) string {
	return GetUriParamString(r, "loc", " and ", false, false)
}

func GetUriPageLimitString(r *http.Request) string {
	vars := r.URL.Query()
	p, ok := vars["PAGE"]
	if !ok {
		log.Info("page param is not exist")
		return ""
	}

	l, ok := vars["LIMIT"]
	if !ok {
		log.Info("limit param is not exist")
		return ""
	}
	li, _ := strconv.Atoi(l[0])
	pi, _ := strconv.Atoi(p[0])
	ls := fmt.Sprintf("limit %d, %d", li*(pi-1), li)

	log.Debug("Limit array:", ls)
	return ls
}

func ExtGetUriPageLimitString(r *http.Request) string {
	vars := r.URL.Query()
	p, ok := vars["page"]
	if !ok {
		log.Info("page param is not exist")
		p = append(p, "1")
	}

	l, ok := vars["limit"]
	if !ok {
		log.Info("limit param is not exist")
		l = append(l, strconv.Itoa(global.MaxLimitData))
	}
	limit, _ := strconv.Atoi(l[0])
	if limit > global.MaxLimitData {
		limit = global.MaxLimitData
	}
	page, _ := strconv.Atoi(p[0])
	limitStr := fmt.Sprintf("limit %d, %d", limit*(page-1), limit)

	log.Debug("limitStr:", limitStr)
	return limitStr
}

func IsJsonContentType(r *http.Request) bool {
	hType := r.Header.Get("Content-Type")
	return strings.Contains(hType, "application/json")
}

func IsValidOAuthUri(r *http.Request) bool {
	vars := mux.Vars(r)
	apiVer := vars["apiVersion"] // 获取Uri
	return apiVer == "v1"
}

func IsVallidContentType(r *http.Request, checkFlag bool) bool {
	log.Debug("IsVallidContentType processing ...")
	/*
		ctype := r.Header["Content-Type"]
		log.Debug("ctype:", ctype)
		if len(ctype) != 0 && !strings.Contains(ctype[0], "application/json") {
			return false
		}
	*/
	if strings.Contains(r.Header.Get("Content-Type"), "application/json") || !checkFlag {
		return true
	}
	return false
}

func CheckParameterName(r *http.Request) []string {
	var errorParams []string
	vars := r.URL.Query()
	for k, v := range vars {
		log.Debug("vars:", k, v)
		if k != "rmUIDs" && k != "fields" {
			errorParams = append(errorParams, k)
		}
	}

	return errorParams
}

func GetRmUIDArr(r *http.Request) []string {
	vars := r.URL.Query()
	rmUIDs, ok := vars["rmUIDs"]
	if !ok {
		log.Info("rmUIDs is not exist")
		return nil
	}

	var rmUIDValues []string
	for _, r := range rmUIDs {
		if r != "" {
			rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`))
		}
	}

	return rmUIDValues
}

func GetAttrNameArr(r *http.Request) []string {
	vars := r.URL.Query()
	fields, ok := vars["fields"]
	if !ok {
		log.Info("attributeNames does not exist")
		return nil
	}
	var attrNames []string
	for _, a := range fields {
		if a != "" {
			attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`))
		}
	}

	return attrNames
}

func CheckValidRmUID(rmUIDs []string) []string {
	log.Debug("CheckValidRmUID processing... ")

	var invalidRmUIDs []string
	for _, r := range rmUIDs {
		if !global.MatchRmUID(config.GetRmUIDRegexpFromConfig(), r) {
			invalidRmUIDs = append(invalidRmUIDs, r)
		}
	}

	return invalidRmUIDs
}

func CheckLocalRmUID(rmUIDs []string) string {
	log.Debug("GetLocalRmUID processing... ")

	rmUID := config.GetRmUIDFromConfig()
	for _, r := range rmUIDs {
		if r == rmUID {
			return rmUID
		}
	}

	return ""
}

func GetParamsArrByName(paramName string, r *http.Request) []string {
	vars := r.URL.Query()
	pns, ok := vars[paramName]
	if !ok {
		log.Infof("%s is not exist", paramName)
		return nil
	}

	var pnArr []string
	for _, pn := range pns {
		if pn != "" {
			pnArr = global.MergeStringArr(pnArr, strings.Split(pn, `,`))
		}
	}

	return pnArr
}

func GetOperationTypeFromHttpRequest(r *http.Request) string {
	for k, v := range r.Header {
		log.Tracef("k:%s, v:%s", k, v)
		if strings.ToLower(k) == "operationtype" && len(v) != 0 {
			log.Trace("OperationType:", v[0])
			return v[0]
		}
	}

	return ""
}

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

	var token string = ""
	var err error
	var ret bool
	// response 414-4 uri too long ? (optional)
	// todo ... ?
	if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() {
		log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig())
		ResponseRequestURITooLong414UriTooLong(w)
		return token, err
	}

	// check media type(content type) only support "application/json"
	// response 415-1
	if !IsJsonContentType(r) {
		log.Error("invalid Content-Type")
		ResponseUnsupportedMediaType415(w)
		return token, err
	}

	// error processing ...
	// 401-1 response
	token, ret = oauth.IsCarriedToken(r)
	if !ret {
		log.Error("accessToken is not carried")
		ResponseUnauthorized401AccessTokenNotCarried(w)
		return token, err
	}

	// 401-2 response
	if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) {
		log.Error("accessToken fails or does not exist")
		ResponseUnauthorized401AccessTokenNotExist(w)
		return token, err
	}

	if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
		_, err = dborm.XormUpdateSessionShakeTime(token)
		if err != nil {
			log.Error("Failed to update session table:", err)
			ResponseUnauthorized401AccessTokenNotExist(w)
			return token, err
		}
	}

	vars := mux.Vars(r)
	apiVer := vars["apiVersion"]
	if apiVer != global.ApiVersionV1 {
		log.Error("Uri is invalid")
		ResponseNotFound404UriNotExist(w, r)
		return token, err
	}

	// response 406-1
	rmUIDValues := GetRmUIDArr(r)
	if rmUIDValues == nil {
		log.Error("missing parameter: rmUIDs")
		ResponseNotAcceptable406MissingParam(w)
		return token, err
	}

	// response 406-2
	errorParams := CheckParameterName(r)
	if errorParams != nil {
		log.Error("parameter name error: ", errorParams)
		ResponseNotAcceptable406ParamError(w, errorParams)
		return token, err
	}

	// response 400-5
	if len(rmUIDValues) == 0 {
		log.Error("rmUIDs is wrong or NULL")
		ResponseBadRequest400WrongParamValue(w)
		return token, err
	}

	// response 414-1
	if len(rmUIDValues) > config.GetYamlConfig().Params.RmUIDMaxNum {
		log.Error("rmUID greater than", config.GetYamlConfig().Params.RmUIDMaxNum)
		ResponseRequestURITooLong414NRMNumExceed(w, config.GetYamlConfig().Params.RmUIDMaxNum)
		return token, err
	}

	return token, nil
}

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

	var token string = ""
	var err error
	var ret bool
	// response 414-4 uri too long ? (optional)
	// todo ... ?
	if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() {
		log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig())
		ResponseRequestURITooLong414UriTooLong(w)
		return token, err
	}

	// check media type(content type) only support "application/json"
	// response 415-1
	if !IsJsonContentType(r) {
		log.Error("Invalid Content-Type")
		ResponseUnsupportedMediaType415(w)
		return token, err
	}

	// error processing ...
	// 401-1 response
	token, ret = oauth.IsCarriedToken(r)
	if !ret {
		log.Error("accessToken is not carried")
		ResponseUnauthorized401AccessTokenNotCarried(w)
		return token, err
	}

	// 401-2 response
	if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) {
		log.Error("accessToken fails or does not exist")
		ResponseUnauthorized401AccessTokenNotExist(w)
		return token, err
	}

	if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
		_, err = dborm.XormUpdateSessionShakeTime(token)
		if err != nil {
			log.Error("Failed to update session table:", err)
			ResponseUnauthorized401AccessTokenNotExist(w)
			return token, err
		}
	}

	vars := mux.Vars(r)
	apiVer := vars["apiVersion"]
	if apiVer != global.ApiVersionV1 {
		log.Error("Uri is invalid")
		ResponseNotFound404UriNotExist(w, r)
		return token, err
	}

	return token, nil
}

func CheckUserPermission(token, method, module, dbname, tbname, pack string) (bool, error) {
	if config.GetYamlConfig().OMC.RBACMode {
		if module == "" {
			module = "*"
		}
		if dbname == "" {
			dbname = "*"
		}
		if tbname == "" {
			tbname = "*"
		}
		exist, err := dborm.IsPermissionAllowed(token, method, module, dbname, tbname, pack)
		if err != nil {
			return false, err
		}
		if !exist {
			return false, nil
		}
	}

	return true, nil
}

func IsLocalhost(host string) bool {
	if strings.Contains(host, "127.0.0.1") || strings.Contains(host, "::1") {
		return true
	}
	return false
}

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

	var token string = ""
	var err error
	var ret bool
	// response 414-4 uri too long ? (optional)
	// todo ... ?
	if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() {
		err = errors.New("request Uri too long")
		log.Errorf("Request Uri too long: bytes=%d, MaxLen=%d", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig())
		ResponseRequestURITooLong414UriTooLong(w)
		return token, err
	}

	/*
		// check media type(content type) only support "application/json"
		// response 415-1
		if !IsVallidContentType(r) {
			err := errors.New("Invalid Content-Type")
			log.Error(err)
			ResponseUnsupportedMediaType415(w)
			return err
		}
	*/

	// error processing ...
	// 401-1 response
	if config.GetYamlConfig().Auth.Token && !IsLocalhost(r.RemoteAddr) {
		token, ret = oauth.IsCarriedToken(r)
		if !ret {
			err = errors.New("accessToken is not carried")
			log.Error(err)
			ResponseUnauthorized401AccessTokenNotCarried(w)
			return token, err
		}

		// 401-2 response
		if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) {
			err = errors.New("accessToken fails or does not exist")
			log.Error(err)
			ResponseUnauthorized401AccessTokenNotExist(w)
			return token, err
		}

		if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
			_, err = dborm.XormUpdateSessionShakeTime(token)
			if err != nil {
				log.Error("Failed to update session table:", err)
				ResponseUnauthorized401AccessTokenNotExist(w)
				return token, err
			}
		}

	}

	vars := mux.Vars(r)
	apiVer := vars["apiVersion"]
	if apiVer != global.ApiVersionV1 {
		err = errors.New("uri is invalid")
		log.Error(err)
		ResponseNotFound404UriNotExist(w, r)
		return token, err
	}

	return token, nil
}

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

	var token string = ""
	var err error
	var ret bool
	// error processing ...
	// 401-1 response
	if config.GetYamlConfig().Auth.Token {
		token, ret = oauth.IsCarriedToken(r)
		if !ret {
			err = errors.New("accessToken is not carried")
			log.Error(err)
			ResponseUnauthorized401AccessTokenNotCarried(w)
			return token, err
		}

		// 401-2 response
		if !dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) {
			err = errors.New("accessToken fails or does not exist")
			log.Error(err)
			ResponseUnauthorized401AccessTokenNotExist(w)
			return token, err
		}

		if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
			_, err = dborm.XormUpdateSessionShakeTime(token)
			if err != nil {
				log.Error("Failed to update session table:", err)
				ResponseUnauthorized401AccessTokenNotExist(w)
				return token, err
			}
		}
	}

	vars := mux.Vars(r)
	apiVer := vars["apiVersion"]
	if apiVer != global.ApiVersionV1 {
		err = errors.New("uri is invalid")
		log.Error(err)
		ResponseNotFound404UriNotExist(w, r)
		return token, err
	}

	return token, nil
}

func ResponseStatusOK200Login(w http.ResponseWriter, token string, user *dborm.User) {
	var oAuthResponse SucceedOAuthResponse
	oAuthResponse.AccessToken = token
	oAuthResponse.Expires = strconv.Itoa((int)(config.GetExpiresFromConfig()))
	oAuthResponse.ChangePasswordFlag = user.ChangePasswordFlag
	oAuthResponse.GroupName = user.GroupName
	ResponseWithJson(w, http.StatusOK, oAuthResponse)
}

func ResponseStatusOK200LoginWhitRP(w http.ResponseWriter, token string, user *dborm.User, roles, perms []string) {
	var oAuthResponse SucceedOAuthResponse
	oAuthResponse.AccessToken = token
	oAuthResponse.Expires = strconv.Itoa((int)(config.GetExpiresFromConfig()))
	oAuthResponse.ChangePasswordFlag = user.ChangePasswordFlag
	oAuthResponse.GroupName = user.GroupName
	oAuthResponse.Roles = roles
	oAuthResponse.Perms = perms
	ResponseWithJson(w, http.StatusOK, oAuthResponse)
}

func ResponseStatusOK200Null(w http.ResponseWriter) {
	response := NullResponse{""}
	ResponseWithJson(w, http.StatusOK, response)
}

func ResponseStatusOK204NoContent(w http.ResponseWriter) {
	ResponseWithJson(w, http.StatusNoContent, "")
}

func ResponseStatusOK201Accepted(w http.ResponseWriter) {
	ResponseWithJson(w, http.StatusAccepted, "")
}

type SSORedirect struct {
	User  string `json:"user"`
	Token string `json:"token"`
}

func ResponseRedirect(w http.ResponseWriter, redirectUrl, user, token string) {
	w.Header().Set("Cache-Control", "must-revalidate, no-store")
	w.Header().Set("Content-Type", " text/html;charset=UTF-8")
	w.Header().Set("Location", redirectUrl) //跳转地址设置
	//w.WriteHeader(http.StatusTemporaryRedirect) //重定向！
	ssoRedirect := &SSORedirect{user, token}
	ResponseWithJson(w, http.StatusTemporaryRedirect, *ssoRedirect)
}

func ResponseBadRequest400RmUIDsIsInvalid(w http.ResponseWriter, rmUIDs []string) {
	errorMessage := ErrorMessage{"1", "rmUIDs is invalid:" + strings.Join(rmUIDs, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}

func ResponseBadRequest400DuplicateSubId(w http.ResponseWriter, SubIds string) {
	errorMessage := ErrorMessage{"2", "Duplicate with resource subscription id:" + SubIds}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}

func ResponseBadRequest400DuplicateAlarmId(w http.ResponseWriter, AlarmIds string) {
	errorMessage := ErrorMessage{"3", "Duplicate with alarm subscription id: " + AlarmIds}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}

func ResponseBadRequest400IncorrectLogin(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"4", "incorrect username and password"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}

func ResponseBadRequest400WrongParamValue(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"5", "wrong parameter value"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}

func ResponseBadRequest400CMCALoginError(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"6", "CMCA centralized authentication login error"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}

func ResponseBadRequest400InvalidJson(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"7", "invalid json format"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusUnauthorized, errorResponse)
}

func ResponseUnauthorized401AccessTokenNotCarried(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"1", "accessToken is not carried"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusUnauthorized, errorResponse)
}

func ResponseUnauthorized401AccessTokenNotExist(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"2", "accessToken fails or does not exist"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusUnauthorized, errorResponse)
}

func ResponseForbidden403NotPermission(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"1", "do not have the operation permissions"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusForbidden, errorResponse)
}

func ResponseForbidden403MultiLoginNotAllowed(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"2", "multiple logins are not allowed"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusForbidden, errorResponse)
}

func ResponseNotFound404UriNotExist(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" {
		ResponseStatusOK204NoContent(w)
		return
	}
	errorMessage := ErrorMessage{"1", "the requested URI does not exist"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404UriNotExistExt(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"1", "the requested URI does not exist"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func CustomResponseNotFound404Handler() http.Handler {
	return http.HandlerFunc(ResponseNotFound404UriNotExist)
}

func ResponseNotFound404NRMNotExist(w http.ResponseWriter, rmUIDs []string) {
	errorMessage := ErrorMessage{"2", "rmUIDs does not exist: " + strings.Join(rmUIDs, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404PMNotExist(w http.ResponseWriter, rmUIDs []string) {
	errorMessage := ErrorMessage{"3", "rmUIDs does not exist: " + strings.Join(rmUIDs, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404AlarmNotExist(w http.ResponseWriter, AlarmIds []string) {
	errorMessage := ErrorMessage{"4", "alarmIds does not exist: " + strings.Join(AlarmIds, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404GetSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
	errorMessage := ErrorMessage{"5", "subscription id does not exist: " + strings.Join(SubIds, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404DeleteSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
	errorMessage := ErrorMessage{"6", "subscription id does not exist: " + strings.Join(SubIds, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404GetAlarmSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
	errorMessage := ErrorMessage{"7", "subscription id does not exist: " + strings.Join(SubIds, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseNotFound404DeleteAlarmSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
	errorMessage := ErrorMessage{"8", "subscription id does not exist: " + strings.Join(SubIds, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotFound, errorResponse)
}

func ResponseMethodNotAllowed405(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" {
		ResponseStatusOK204NoContent(w)
		return
	}
	errorMessage := ErrorMessage{"1", "method not allowed"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusMethodNotAllowed, errorResponse)
}

func CustomResponseMethodNotAllowed405Handler() http.Handler {
	return http.HandlerFunc(ResponseMethodNotAllowed405)
}

func ResponseNotAcceptable406MissingParam(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"1", "missing parameter: rmUIDs"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotAcceptable, errorResponse)
}

func ResponseNotAcceptable406ParamError(w http.ResponseWriter, errorParamsName []string) {
	errorMessage := ErrorMessage{"2", "parameter name error: " + strings.Join(errorParamsName, ",")}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotAcceptable, errorResponse)
}

func ResponseNotAcceptable406QuerySQLError(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"3", "wrong or non-query SQL statement"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusNotAcceptable, errorResponse)
}

func ResponseRequestEntityTooLarge413SubscriptionExceed(w http.ResponseWriter, num int) {
	errorMessage := ErrorMessage{"1", "the number of subscriptions greater than " + strconv.Itoa(num)}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusRequestEntityTooLarge, errorResponse)
}

func ResponseRequestEntityTooLarge413BodyToLarge(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"2", "the request entity too large"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusRequestEntityTooLarge, errorResponse)
}

func ResponseRequestURITooLong414NRMNumExceed(w http.ResponseWriter, num int) {
	errorMessage := ErrorMessage{"1", "the number of NRM rmUIDs greater than " + strconv.Itoa(num)}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}

func ResponseRequestURITooLong414AlarmNumExceed(w http.ResponseWriter, num int) {
	errorMessage := ErrorMessage{"2", "the number of alarmIds greater than " + strconv.Itoa(num)}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}

func ResponseRequestURITooLong414PMNumExceed(w http.ResponseWriter, num int) {
	errorMessage := ErrorMessage{"3", "the number of PM rmUIDs greater than " + strconv.Itoa(num)}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}

func ResponseRequestURITooLong414UriTooLong(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"3", "request URI too long"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}

func ResponseUnsupportedMediaType415(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"1", "unsupported media type"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusUnsupportedMediaType, errorResponse)
}

func ResponseInternalServerError500NFConnectRefused(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"1", "internal server error, NF connnect refused"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusInternalServerError, errorResponse)
}

func ResponseInternalServerError500DatabaseOperationFailed(w http.ResponseWriter) {
	errorMessage := ErrorMessage{"2", "internal server error, database opration failed"}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusInternalServerError, errorResponse)
}

func ResponseInternalServerError500ProcessError(w http.ResponseWriter, err error) {
	em := fmt.Sprintf("internal server error: %v", err)
	errorMessage := ErrorMessage{"3", em}
	errorResponse := ErrorResponse{errorMessage}
	ResponseWithJson(w, http.StatusInternalServerError, errorResponse)
}

func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) {
	log.Trace("payload: ", payload)

	response, _ := json.Marshal(payload)
	SetResponseHeader(w)
	w.WriteHeader(code)
	w.Write(response)
	log.Trace("Response Code:", code)
	log.Trace("Response Body:", string(response))
}

func ResponseWithZip(w http.ResponseWriter, payload interface{}) {
	response, _ := json.Marshal(payload)
	SetResponseHeader(w)
	w.WriteHeader(http.StatusOK)
	w.Write(response)
	log.Trace("Response Body:", string(response))
}

func TransportResponse(w http.ResponseWriter, code int, payload []byte) {
	var tempBody, transBody interface{}
	switch code {
	case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
		json.Unmarshal(payload, &tempBody)
		transBody = DataResponse{tempBody}
	default:
		json.Unmarshal(payload, &tempBody)
		transBody = ErrorResponse{tempBody}
	}
	response, _ := json.Marshal(transBody)
	log.Trace("transBody: ", transBody)
	SetResponseHeader(w)
	w.WriteHeader(code)
	w.Write(response)
	log.Trace("response: ", string(response))
}

func ResponseWithUnsortJson(w http.ResponseWriter, code int, payload map[string]interface{}) {
	var om global.OrderedMap
	om.Map = payload
	response, _ := om.MarshalJson()
	log.Trace("payload: ", payload)
	SetResponseHeader(w)
	w.WriteHeader(code)
	w.Write(response)
	log.Trace("response: ", string(response))
}

func ResponseErrorWithJson(w http.ResponseWriter, code int, nameValue interface{}) {
	response := make(map[string]interface{})
	response["error"] = nameValue
	ResponseWithJson(w, code, response)
}

func SetCommonResponseHeader(w http.ResponseWriter) {
	// 设置Vary头部
	w.Header().Set("Vary", "Origin")
	w.Header().Set("Keep-Alive", "timeout=5")
	// To solve cross domain issue
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "*")
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Access-Control-Allow-Credentials", "true")
	// 响应最大时间值
	w.Header().Set("Access-Control-Max-Age", "31536000")
}

func SetResponseHeader(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	SetCommonResponseHeader(w)
}

// Creates a new file upload http request with optional extra params
func ResponseUploadFile(w http.ResponseWriter, code int, params map[string]string, paramName, path string) {
	file, err := os.Open(path)
	if err != nil {
		log.Errorf("Failed to open: %v", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(paramName, filepath.Base(path))
	if err != nil {
		log.Error("Failed to CreateFormFile:", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}
	_, err = io.Copy(part, file)
	if err != nil {
		log.Error("Failed to Copy:", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}

	for key, val := range params {
		_ = writer.WriteField(key, val)
	}

	err = writer.Close()
	if err != nil {
		log.Error("Failed to Close:", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}

	SetCommonResponseHeader(w)
	w.Header().Set("Content-Type", writer.FormDataContentType())
	w.WriteHeader(code)
	w.Write(body.Bytes())
}

func ResponseFile(w http.ResponseWriter, code int, filePath string) {
	fileBytes, err := os.ReadFile(filePath)
	if err != nil {
		log.Error("Failed to ReadFile:", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}
	SetCommonResponseHeader(w)
	w.Header().Set("Content-Type", "application/octet-stream")
	w.WriteHeader(code)
	w.Write(fileBytes)
}

func ResponseFileWithNameAndMD5(w http.ResponseWriter, code int, fileName, path, md5Sum string) {
	filePath := path + "/" + fileName
	fileBytes, err := os.ReadFile(filePath)
	if err != nil {
		log.Error("Failed to ReadFile:", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}
	SetCommonResponseHeader(w)
	encodedFileName := url.PathEscape(fileName)
	w.Header().Set("Content-Disposition", `attachment; filename="`+encodedFileName+`"`)
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("User-File", fileName)
	w.Header().Set("MD5-Sum", md5Sum)
	w.WriteHeader(code)
	w.Write(fileBytes)
}

func ResponseHtmlContent(w http.ResponseWriter, code int, filePath string) {
	htmlContent, err := os.ReadFile(filePath)
	if err != nil {
		log.Error("Failed to ReadFile:", err)
		ResponseInternalServerError500ProcessError(w, err)
		return
	}

	SetCommonResponseHeader(w)
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(code)
	w.Write(htmlContent)
}

// RouterItem 路由项
type RouterItem struct {
	Method     string
	Pattern    string
	Handler    http.HandlerFunc
	Middleware mux.MiddlewareFunc
}
