package dborm

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"strings"

	"be.ems/features/sys_role/model"
	"be.ems/lib/log"
	"be.ems/lib/oauth"

	_ "github.com/go-sql-driver/mysql"
	"xorm.io/xorm"
)

const (
	TableNameMeasureTask = "measure_task"
	TableNameNeInfo      = "ne_info"
)

type Menu struct {
	Id       int    `json:"id"`
	Title    string `json:"title"`
	Icon     string `json:"icon"`
	Href     string `json:"href"`
	ParentId int    `json:"parent_id`
	Remark   int    `json:"remark"`
}

type DatabaseClient struct {
	dbType            string
	dbUrl             string
	dbConnMaxLifetime time.Duration
	dbMaxIdleConns    int
	dbMaxOpenConns    int
	IsShowSQL         bool

	XEngine *xorm.Engine
}

var DbClient DatabaseClient

func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
	DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
		dbUser, dbPassword, dbHost, dbPort, dbName)
	DbClient.dbType = dbType
	DbClient.dbConnMaxLifetime = 0
	DbClient.dbMaxIdleConns = 0
	DbClient.dbMaxOpenConns = 0
	if log.GetLevel() == log.LOG_TRACE {
		DbClient.IsShowSQL = true
	}
	log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
		dbType, dbUser, dbHost, dbPort, dbName)

	var err error
	DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
	if err != nil {
		log.Error("Failed to connet database:", err)
		return err
	}
	DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
	DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
	DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
	if DbClient.IsShowSQL {
		DbClient.XEngine.ShowSQL(true)
	}
	xEngine = DbClient.XEngine

	return nil
}

// func InitDbClient() error {
// 	db := config.GetYamlConfig().Database
// 	DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", db.User, db.Password, db.Host, db.Port, db.Name)
// 	DbClient.dbType = db.Type
// 	DbClient.dbConnMaxLifetime = 0
// 	DbClient.dbMaxIdleConns = 0
// 	DbClient.dbMaxOpenConns = 0
// 	if log.GetLevel() == log.LOG_TRACE {
// 		DbClient.IsShowSQL = true
// 	}
// 	log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s", DbClient.dbType, db.User, db.Host, db.Port, db.Name)
// 	var err error
// 	DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
// 	if err != nil {
// 		log.Error("Failed to connet database:", err)
// 		return err
// 	}
// 	DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
// 	DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
// 	DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
// 	if DbClient.IsShowSQL {
// 		DbClient.XEngine.ShowSQL(true)
// 	}
// 	xEngine = DbClient.XEngine

// 	return nil
// }

var xEngine *xorm.Engine

func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) {
	sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
		dbUser, dbPassword, dbHost, dbPort, dbName)
	log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
		dbType, dbUser, dbHost, dbPort, dbName)
	var err error
	xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine
	if err != nil {
		log.Error("Failed to connect database:", err)
		return nil, err
	}
	if log.GetLevel() == log.LOG_TRACE {
		xEngine.ShowSQL(true)
	}
	return xEngine, nil
}

func ConstructInsertSQL(tableName string, insertData interface{}) (string, []string) {
	log.Debug("ConstructInsertSQL processing... ")
	log.Debug("Request insertData:", insertData)

	var sql []string
	var dataTag string
	for t, d := range insertData.(map[string]interface{}) {
		log.Tracef("t: %v d: %v", t, d)
		dataTag = t

		for i, r := range d.([]interface{}) {
			var cl, vl string
			log.Tracef("i: %v r: %v", i, r)
			for c, v := range r.(map[string]interface{}) {
				log.Tracef("c: %v v: %v", c, v)
				if cl == "" {
					cl = fmt.Sprintf("%s", c)
				} else {
					cl = fmt.Sprintf("%s, %s", cl, c)
				}
				if vl == "" {
					vl = fmt.Sprintf("'%v'", v)
				} else {
					vl = fmt.Sprintf("%s, '%v'", vl, v)
				}

				log.Tracef("cl: %s vl: %s", cl, vl)
			}
			sql = append(sql, "insert into "+tableName+"("+cl+")"+" values("+vl+")")
		}

		log.Debug("sql:", sql)
	}

	return dataTag, sql
}

func InsertDataWithJson(insertData interface{}) (int64, error) {
	log.Debug("InsertDataWithJson processing... ")

	var data map[string]interface{}
	var tableName string
	for k, v := range insertData.(map[string]interface{}) {
		log.Tracef("k: %v v: %v", k, v)
		tableName = k
		data = v.(map[string]interface{})
	}

	log.Tracef("data: %v", data)
	xSession := xEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.Insert(data, tableName)
	xSession.Commit()

	return affected, err
}

type NeInfo struct {
	Id         int    `json:"id" xorm:"pk 'id' autoincr"`
	NeType     string `json:"neType" xorm:"ne_type"`
	NeId       string `json:"neId" xorm:"ne_id"`     // neUID/rmUID 网元唯一标识
	RmUID      string `json:"rmUid" xorm:"rm_uid"`   // neUID/rmUID网元UID
	NeName     string `json:"neName" xorm:"ne_name"` // NeName/UserLabel 网元名称/网元设备友好名称
	Ip         string `json:"ip" xorm:"ip"`
	Port       string `json:"port" xorm:"port"`
	PvFlag     string `json:"pvFlag" xorm:"pv_flag"`         // 网元虚实性标识 VNF/PNF: 虚拟/物理
	NeAddress  string `json:"neAddress" xorm:"ne_address"`   // 只对PNF
	Province   string `json:"province" xorm:"province"`      // 网元所在省份
	VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称
	Dn         string `json:"dn" xorm:"dn"`                  // 网络标识
	Status     int    `json:"status" xorm:"status"`
	UpdateTime string `json:"-" xorm:"-"`
}

func XormGetMySQLVersion() (string, error) {
	var versionInfo string = ""

	var ver, verComment, verCompileOS, verCompile string
	_, err := xEngine.SQL("SHOW VARIABLES LIKE 'version'").Get(&ver, &ver)
	if err != nil {
		return versionInfo, err
	}

	_, err = xEngine.SQL("SHOW VARIABLES LIKE 'version_comment'").Get(&verComment, &verComment)
	if err != nil {
		return versionInfo, err
	}

	_, err = xEngine.SQL("SHOW VARIABLES LIKE 'version_compile_os'").Get(&verCompileOS, &verCompileOS)
	if err != nil {
		return versionInfo, err
	}

	_, err = xEngine.SQL("SHOW VARIABLES LIKE 'version_compile_machine'").Get(&verCompile, &verCompile)
	if err != nil {
		return versionInfo, err
	}

	versionInfo = fmt.Sprintf("%s %s, for %s (%s)", ver, verComment, verCompileOS, verCompile)
	return versionInfo, nil
}

func XormGetNeInfo(neType string, neId string) (*NeInfo, error) {
	log.Debug("XormGetNeInfo processing... ")

	neInfo := new(NeInfo)
	has, err := xEngine.Where("ne_type=? and ne_id=?", strings.ToUpper(neType), neId).Get(neInfo)
	if err != nil {
		log.Error("Failed to get table ne_info from database:", err)
		return nil, err
	} else if !has {
		log.Infof("Not found ne_info from database, neType=%s, neId=%s", neType, neId)
		return nil, nil
	}

	log.Debug("NE Info:", neInfo)
	return neInfo, nil
}

func XormGetNeInfoByRmUID(neType string, rmUID string) (*NeInfo, error) {
	log.Debug("XormGetNeInfoByRmUID processing... ")

	neInfo := new(NeInfo)
	has, err := xEngine.Where("ne_type=? and rm_uid=?", strings.ToUpper(neType), rmUID).Get(neInfo)
	if err != nil {
		log.Error("Failed to get table ne_info from database:", err)
		return nil, err
	} else if !has {
		log.Infof("Not found ne_info from database, neType=%s, neId=%s", neType, rmUID)
		return nil, nil
	}

	log.Debug("NE Info:", neInfo)
	return neInfo, nil
}

func XormGetAllNeInfo(nes *[]NeInfo) (*[]NeInfo, error) {
	log.Debug("XormGetAllNeInfo processing... ")

	ne := new(NeInfo)
	rows, err := xEngine.Table("ne_info").Rows(ne)
	if err != nil {
		log.Error("Failed to get table ne_info from database:", err)
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(ne)
		if err != nil {
			log.Error("Failed to get table ne_info from database:", err)
			return nil, err
		}
		*nes = append(*nes, *ne)
	}
	log.Trace("nes:", nes)
	return nes, nil
}

func XormGetNeInfoByNeType(neType string, nes *[]NeInfo) error {
	log.Debug("XormGetNeInfoByNeType processing... ")

	ne := new(NeInfo)
	rows, err := xEngine.Table("ne_info").Where("ne_type=?", neType).Rows(ne)
	if err != nil {
		log.Error("Failed to get table ne_info from database:", err)
		return err
	}
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(ne)
		if err != nil {
			log.Error("Failed to get table ne_info from database:", err)
			return err
		}
		*nes = append(*nes, *ne)
	}

	return nil
}

func XormGetNeInfo2(neType string, neIDs []string, nes *[]NeInfo) error {
	log.Info("XormGetNeInfo2 processing... ")

	ne := new(NeInfo)
	var rows *xorm.Rows
	var err error
	if len(neIDs) == 0 {
		rows, err = xEngine.Table("ne_info").
			Where("ne_type=?", neType).
			Rows(ne)
	} else {
		rows, err = xEngine.Table("ne_info").
			In("ne_id", neIDs).
			And("ne_type=?", neType).
			Rows(ne)
	}
	if err != nil {
		log.Error("Failed to get table ne_info from database:", err)
		return err
	}
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(ne)
		if err != nil {
			log.Error("Failed to get table ne_info from database:", err)
			return err
		}
		*nes = append(*nes, *ne)
	}

	return nil
}

func XormInsertNeInfo(neInfo *NeInfo) (int64, error) {
	log.Debug("XormInsertNeInfo processing... ")

	var affected int64 = 0
	var err error = nil

	xSession := xEngine.NewSession()
	defer xSession.Close()
	ex, _ := xEngine.Table("ne_info").Where("status = '1' and ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId).Exist()
	if ex {
		neInfo.Status = 0
		affected, err = xSession.Where("ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId).Update(neInfo)
	} else {
		affected, err = xSession.InsertOne(neInfo)
	}
	xSession.Commit()
	return affected, err
}

func XormUpdateNeInfo(neInfo *NeInfo) (int64, error) {
	log.Debug("XormUpdateNeInfo processing... ")

	xSession := xEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.ID(neInfo.Id).MustCols("status").Update(neInfo)
	xSession.Commit()
	return affected, err
}

func XormDeleteNeInfo(neInfo *NeInfo) (int64, error) {
	log.Debug("XormDeleteNeInfo processing... ")

	xSession := xEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.Where("ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId).Delete(neInfo)
	xSession.Commit()
	return affected, err
}

func XormParseResult(body []byte) ([]NeInfo, error) {
	log.Debug("XormParseResult processing... ")

	data := make(map[string]interface{})
	err := json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}
	var neInfo []NeInfo
	var re interface{}
	if data["data"] == nil {
		return nil, errors.New("The data is Not found")
	}
	for _, d := range data["data"].([]interface{}) {
		if d == nil {
			return nil, errors.New("The data is Not found")
		}
		for _, re = range d.(map[string]interface{}) {
			if re == nil {
				return nil, errors.New("The data is Not found")
			}
			for _, rc := range re.([]interface{}) {
				if rc == nil {
					return nil, errors.New("The data is Not found")
				}
				var s NeInfo
				record := rc.(map[string]interface{})
				s.NeName = fmt.Sprintf("%v", record["ne_name"])
				s.NeId = fmt.Sprintf("%v", record["ne_id"])
				s.NeType = fmt.Sprintf("%v", strings.ToLower(record["ne_type"].(string)))
				s.Ip = fmt.Sprintf("%v", record["ip"])
				s.Port = fmt.Sprintf("%v", record["port"])
				s.PvFlag = fmt.Sprintf("%v", record["pv_flag"])

				neInfo = append(neInfo, s)
			}
		}
	}

	log.Debug("neInfo:", neInfo)
	return neInfo, nil
}

type ParamConfig struct {
	//	Id         int    `json:"id" xorm:"pk 'id' autoincr"`
	NeType     string `json:"neType"`
	NeId       string `json:"neId"`
	TopTag     string `json:"topTag"`
	TopDisplay string `json:"topDisplay"`
	ParamJson  string `json:"paramJson"`
}

func XormInsertParamConfig(mapJson *map[string]interface{}) (int64, error) {
	var affected, a int64
	var err error
	paramConfig := new(ParamConfig)
	for n, d := range *mapJson {
		if d == nil {
			break
		}
		log.Debugf("n: %s", n)

		for t, p := range d.(map[string]interface{}) {
			if p == nil {
				break
			}
			log.Debug("t:", t)
			log.Debug("p:", p)
			for k, v := range p.(map[string]interface{}) {
				log.Debug("k, v: ", k, v)
				if k == "display" {
					paramConfig.TopDisplay = fmt.Sprintf("%v", v)

				} else {
					pc, _ := json.Marshal(v)
					paramConfig.ParamJson = fmt.Sprintf("{\"%v\":%v}", k, string(pc))
				}
			}

			paramConfig.NeType = strings.ToUpper(n)
			paramConfig.NeId = ""
			paramConfig.TopTag = t
			//			paramConfig.TopDisplay = p["display"]
			//			paramConfig.ParamJson = p.(string)

			log.Debug("paramConfig:", paramConfig)

			xSession := xEngine.NewSession()
			defer xSession.Close()
			_, err = xSession.Table("param_config").Where("ne_type = ? and top_tag = ?", paramConfig.NeType, paramConfig.TopTag).Delete()
			if err != nil {
				log.Error("Failed to insert param_config:", err)
			}
			a, err = xSession.Insert(paramConfig)
			if err != nil {
				log.Error("Failed to insert param_config:", err)
			}
			affected += a
			xSession.Commit()
		}
	}

	return affected, err
}

func ConstructUpdateSQLArray(tableName string, updateData interface{}, whereCondition string) (string, []string) {
	log.Debug("ConstructUpdateSQL processing... ")
	log.Debug("Request updateData:", updateData)

	var sql []string
	var tblName string
	for t, d := range updateData.(map[string]interface{}) {
		log.Tracef("t: %v d: %v", t, d)
		tblName = t

		for i, r := range d.([]interface{}) {
			var cv string
			log.Tracef("i: %v r: %v", i, r)
			for c, v := range r.(map[string]interface{}) {
				log.Tracef("c: %v v: %v", c, v)
				if cv == "" {
					cv = fmt.Sprintf("`%s`='%s'", c, v)
				} else {
					cv = fmt.Sprintf("%s,`%s`='%s'", cv, c, v)
				}

				log.Tracef("cv: %s", cv)
			}
			sql = append(sql, "UPDATE "+tableName+" SET "+cv+" WHERE "+whereCondition)
		}

		log.Debug("sql:", sql)
	}

	return tblName, sql
}

func ConstructUpdateSQL(tableName string, updateData interface{}, whereCondition string) (string, []string) {
	log.Debug("ConstructUpdateSQL processing... ")
	log.Debug("Request updateData:", updateData)

	var sql []string
	var tblName string
	for t, d := range updateData.(map[string]interface{}) {
		log.Tracef("t: %v d: %v", t, d)
		tblName = t

		var cv string
		for c, v := range d.(map[string]interface{}) {
			log.Tracef("c: %v v: %v", c, v)
			if cv == "" {
				//cv = fmt.Sprintf("`%s`=%s", c, v)
				cv = fmt.Sprintf("`%s`='%s'", c, v)
			} else {
				//cv = fmt.Sprintf("%s,`%s`=%s", cv, c, v)
				cv = fmt.Sprintf("%s,`%s`='%s'", cv, c, v)
			}

			log.Tracef("cv: %s", cv)
		}
		sql = append(sql, "UPDATE "+tableName+" SET "+cv+" WHERE "+whereCondition)

		log.Debug("sql:", sql)
	}

	return tblName, sql
}

func ConstructDeleteSQL(tableName string, whereCondition string) string {
	log.Debug("ConstructDeleteSQL processing... ")

	var sql string

	sql = "DELETE from " + tableName + " WHERE " + whereCondition
	log.Debug("sql:", sql)
	return sql
}

type TaskStatus string

const (
	MeasureTaskStatusInactive = "Inactive"
	MeasureTaskStatusActive   = "Active"
	MeasureTaskStatusSuspend  = "Suspend"
	MeasureTaskStatusDeleted  = "Deleted"
)

type MTask struct {
	Id int `json:"id" xorm:"pk 'id' autoincr"`

	NeSet struct {
		NEs []string `json:"nes"`
	} `json:"neSet" xorm:"ne_set"`
	KpiSet struct {
		Code string   `json:"Code"`
		KPIs []string `json:"KPIs`
	} `json:"kpiSet" xorm:"kpi_set"`
	StartTime string `json:"startTime" xorm:"start_time"`
	EndTime   string `json:"endTime" xorm:"end_time"`
	Periods   []struct {
		Start string `json:"start"`
		End   string `json:"end"`
	} `json:"Periods" xorm:"periods`
	Schedule struct {
		Type string `json:"type"`
		Days []int  `json:"days"`
	} `json:"schedule" xorm:"schedule"`
	GranulOption string `json:"granulOption" xorm:"granul_option"`
	Status       string `json:"status" xorm:"status"`
	CreateTime   string `json:"createTime" xorm:"create_time"`
	UpdateTime   string `json:"updateTime" xorm:"update_time"`
	DeleteTime   string `json:"deleteTime xorm:"delete_time"`
}

type ScheduleJ struct {
	Type string `json:"Type"`
	Days []int  `json:"Days"`
}

type Period struct {
	Start string `json:"Start"`
	End   string `json:"End"`
}

type KpiSetJ struct {
	Code string   `json:"Code"` // 统计编码 如：SMFHA01
	KPIs []string `json:"KPIs`  // 指标项集合 ["SMF.AttCreatePduSession", "SMF.AttCreatePduSession._Dnn"]
}

type MeasureTask struct {
	Id           int         `json:"id" xorm:"pk 'id' autoincr"`
	NeType       string      `json:"neType" xorm:"ne_type"`
	NeIds        []string    `json:"neIds" xorm:"ne_ids"`
	KpiSet       []KpiSetJ   `json:"KPISet" xorm:"kpi_set"`
	StartTime    string      `json:"startTime" xorm:"start_time"`
	EndTime      string      `json:"endTime" xorm:"end_time"`
	Periods      []Period    `json:"Periods" xorm:"periods`
	Schedule     []ScheduleJ `json:"Schedule" xorm:"schedule"`
	GranulOption string      `json:"granulOption" xorm:"granul_option"`
	Status       string      `json:"status" xorm:"status"`
	AccountID    string      `json:"accountId" xorm:"account_id"`
	Comment      string      `json:"comment" xorm:"comment"`
	CreateTime   string      `json:"createTime" xorm:"create_time"`
	UpdateTime   string      `json:"updateTime" xorm:"update_time"`
	DeleteTime   string      `json:"deleteTime xorm:"delete_time"`
}

func GetMeasureTask(taskId int) (*MeasureTask, error) {
	log.Debug("GetMeasureTask processing... ")

	measureTask := new(MeasureTask)
	has, err := xEngine.Table("measure_task").Where("id=?", taskId).Get(measureTask)
	if err != nil || !has {
		log.Error("Failed to get table measure_task from database:", err)

		return nil, err
	}

	log.Debug("Measure Task:", measureTask)
	return measureTask, nil
}

func XormGetActiveMeasureTask(measureTasks *[]MeasureTask) (*[]MeasureTask, error) {
	log.Debug("XormGetActiveMeasureTask processing... ")

	measureTask := new(MeasureTask)
	rows, err := xEngine.Table("measure_task").Where("status='Active'").Rows(measureTask)
	if err != nil {
		log.Error("Failed to get table measure_task:", err)
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(measureTask)
		if err != nil {
			log.Error("Failed to get table measure_task from database:", err)
			return nil, err
		}
		*measureTasks = append(*measureTasks, *measureTask)
	}
	log.Debug("measureTasks:", measureTasks)
	return measureTasks, nil
}

func GetTableByWhere(whereCondition string, tableName string) (*[]interface{}, error) {
	log.Debug("GetTableByWhere processing... ")

	rows := new([]interface{})
	has, err := xEngine.Table(tableName).Where(whereCondition).Get(rows)
	if err != nil {
		log.Errorf("Failed to get table %s from database:%v", tableName, err)
		return nil, err
	} else if has == false {
		log.Infof("Not found table %s from database:where=%d", tableName, whereCondition)
		return nil, nil
	}

	log.Debugf("%s:%v", tableName, rows)
	return rows, nil
}

func GetTableById(id int, tableName string) (*[]interface{}, error) {
	log.Debug("GetTableById processing... ")

	rows := new([]interface{})
	has, err := xEngine.Table(tableName).ID(id).Get(rows)
	if err != nil {
		log.Errorf("Failed to get table %s from database:id=%d, %v", tableName, id, err)
		return nil, err
	} else if has == false {
		log.Infof("Not found table %s from database:id=%d", tableName, id)
		return nil, nil
	}

	log.Debugf("%s:%v", tableName, rows)
	return rows, nil
}

func XormUpdateTableById(id int, tableName string, tbInfo interface{}) (int64, error) {
	log.Debug("XormUpdateTableById processing...id: ", id)

	affected, err := xEngine.Table(tableName).ID(id).Update(tbInfo)
	if err != nil {
		log.Errorf("Failed to update table %s from database:%v", tableName, err)
		return 0, err
	}

	return affected, nil
}

func XormUpdateTableByWhere(whereCondition string, tableName string, tbInfo interface{}) (int64, error) {
	log.Debug("UpdateTableByWhere processing... ")

	affected, err := xEngine.Table(tableName).Where(whereCondition).Update(tbInfo)
	if err != nil {
		log.Errorf("Failed to update table %s from database:%v", tableName, err)
		return 0, err
	}

	return affected, nil
}

type User struct {
	Id                 int    `json:"id" xorm:"pk 'id' autoincr"`
	AccountId          string `json:"accountId"`
	Name               string `json:"name" xorm:"name"`
	Sn                 string `json:"sn"`
	Gender             string `json:"gender"`
	Description        string `json:"description"`
	TelephoneNumber    string `json:"telephoneNumber" xorm:"telephone_number"`
	Mobile             string `json:"mobile"`
	Email              string `json:"email" xorm:"email"`
	StartTime          string `json:"startTime" xorm:"start_time"`
	EndTime            string `json:"endTime" xorm:"end_time"`
	IdCardNumber       string `json:"idCardNumber"`
	EmployeeNumber     string `json:"employeeNumber"`
	Organize           string `json:"organize"`
	EmployeeType       string `json:"employeeType"`
	SupporterCorpName  string `json:"supporterCorpName"`
	RealName           string `json:"realName" xorm:"real_name"`
	Password           string `json:"password" xorm:"password"`
	PasswordSha512     string `json:"passwordSha512"`
	ChangePasswordFlag int    `json:"changePasswordFlag"`
	PasswordExpiration string `json:"passwordExpiration"`
	Status             string `json:"status"`
	UserExpiration     string `json:"userExpiration"`
	GroupName          string `json:"groupId" xorm:"group_name"`
	Profile            string `json:"profile" xorm:"profile"`
	Phone              string `json:"phone" xorm:"phone"`
	CreateTime         string `json:"createTime" xorm:"create_time"`
	UpdateTime         string `json:"updateTime" xorm:"update_time"`

	// 角色对象组
	Roles []model.SysRole `json:"roles" xorm:"-"`
}

// 记录密码登录错误次数
func pwdErrCountAdd(accountId, profileStr string, reset bool) int {
	if profileStr == "" {
		profileStr = "{}"
	}
	profile := make(map[string]any)
	count := 0
	timeMlli := time.Now().UnixMilli()

	// 反序列去值
	err := json.Unmarshal([]byte(profileStr), &profile)
	if err != nil {
		log.Error("json Unmarshal:%s", err.Error())
		return 0
	}

	// 读取配置信息 登录策略设置
	result, err := XormGetConfig("Security", "loginSecurity")
	if err != nil {
		return 0
	}
	data := make(map[string]any)
	err = json.Unmarshal([]byte(result["value_json"].(string)), &data)
	if err != nil {
		return 0
	}
	limitNum := data["limit_num"].(string)
	passwordLimitTime := data["password_limit_time"].(string)

	// 重置
	if reset {
		// xEngine.Exec("UPDATE user SET status = 'Active' WHERE account_id = ?", accountId)
		profile["pwdErrCount"] = float64(0)
		profile["pwdErrTime"] = 0
	} else {
		if v, ok := profile["pwdErrTime"]; ok && v != nil {
			// 获取当前时间
			currentTime := time.Now()

			// 获取给定的时间戳（毫秒）
			timestamp := int64(v.(float64)) // 要比较的时间戳（毫秒）
			// 将时间戳转换为时间类型
			tm := time.Unix(timestamp/1000, (timestamp%1000)*int64(time.Millisecond))

			// 计算当前时间与给定时间之间的差值
			duration := currentTime.Sub(tm)

			// // 比较差值是否超过30分钟
			// if duration.Minutes() > 30 {
			// 	xEngine.Exec("UPDATE user SET status = 'Active' WHERE account_id = ?", accountId)
			// 	profile["pwdErrCount"] = float64(0)
			// 	profile["pwdErrTime"] = 0
			// }

			// 比较差值是否小于限定时间s
			passwordLimitTimeInt, err := strconv.Atoi(passwordLimitTime)
			if err != nil {
				passwordLimitTimeInt = 0
			}
			if duration.Seconds() > float64(passwordLimitTimeInt) {
				// xEngine.Exec("UPDATE user SET status = 'Active' WHERE account_id = ?", accountId)
				profile["pwdErrCount"] = float64(0)
				profile["pwdErrTime"] = 0
			}
		}

		if v, ok := profile["pwdErrCount"]; ok && v != nil {
			count = int(v.(float64)) + 1
			profile["pwdErrCount"] = count
			profile["pwdErrTime"] = timeMlli
			// 错误最大后锁定
			limitNumInt, err := strconv.Atoi(limitNum)
			if err != nil {
				limitNumInt = 0
			}
			// if count == limitNumInt {
			// 	_, err := xEngine.Exec("UPDATE user SET status = 'Locked' WHERE account_id = ?", accountId)
			// 	if err != nil {
			// 		return count
			// 	}
			// }
			if count >= limitNumInt {
				return count
			}
		} else {
			count = 1
			profile["pwdErrCount"] = count
			profile["pwdErrTime"] = timeMlli
		}
	}

	// 序列后记录
	strByte, err := json.Marshal(profile)
	if err != nil {
		log.Error("json Marshal:%s", err.Error())
		return count
	}
	_, err = xEngine.Exec("UPDATE user SET profile = ? WHERE account_id = ?", string(strByte), accountId)
	if err != nil {
		return count
	}
	return count
}

func XormCheckLoginUser(name, password, cryptArgo string) (bool, *User, error) {
	log.Info("XormCheckLoginUser processing... ")

	user := new(User)
	//	has, err := xEngine.Table("user").Where("name='%s' and password=PASSWORD('%s')", name, password).Get(user)
	switch cryptArgo {
	case "mysql":
		has, err := xEngine.SQL("select * from user where account_id=? and password=PASSWORD(?)", name, password).Exist()
		if err != nil || has == false {
			log.Error("Failed to check user from database:", err)

			return false, nil, err
		}
	case "md5":
		has, err := xEngine.
			SQL("select * from user where account_id=? and password=MD5(?)", name, password).Exist()
		if err != nil || has == false {
			log.Error("Failed to check user from database:", err)
			return false, nil, err
		}
	case "bcrypt":
		has, err := xEngine.Table("user").Where("account_id=?", name).Get(user)
		if err != nil || !has {
			log.Error("Failed to get user from database:", err)
			return false, nil, err
		}
		if oauth.BcryptCompare(user.Password, password) != nil {
			err := errors.New("Incorrect user name or password")
			log.Error(err)
			// 记录错误
			errCoutn := pwdErrCountAdd(user.AccountId, user.Profile, false)
			if errCoutn > 3 {
				// 登录失败次数过多，请30分钟后重试
				return false, nil, errors.New("Login failed too many times, please retry after 30 minutes")
			}
			return false, nil, err
		}
		// 重置错误次数
		pwdErrCountAdd(user.AccountId, user.Profile, true)
	default:
		errMsg := "Incorrect crypt algoritmo"
		log.Error("crypt:%s", errMsg)
		return false, nil, errors.New(errMsg)
	}

	// enum('Active','Closed','Locked','Pending')
	errMsg := ""
	switch user.Status {
	case "Closed":
		errMsg = "Account disabled" // 账户已禁用
	case "Locked":
		errMsg = "Account locked" // 账户已锁定
	case "Pending":
		// 	errMsg = "账户已挂起"
		_, err := xEngine.Exec("UPDATE user SET status = 'Active' WHERE account_id = ?", user.AccountId)
		if err != nil {
			return false, nil, err
		}
	}
	if errMsg != "" {
		log.Error("user Status:%s", errMsg)
		return false, nil, errors.New(errMsg)
	}

	// 密码到期时间
	if user.PasswordExpiration != "" {
		arr := strings.Split(user.PasswordExpiration, " ")
		if len(arr) > 0 {
			t, err := time.Parse("2006-01-02", arr[0])
			if err != nil {
				return false, nil, err
			}
			if t.Before(time.Now()) {
				errMsg := "Password expiration time" // 密码到期时间
				// 读取配置信息
				result, err := XormGetConfig("Security", "pwdStrong")
				if err != nil {
					return false, nil, err
				}
				data := make(map[string]any)
				err = json.Unmarshal([]byte(result["value_json"].(string)), &data)
				if err != nil {
					log.Error("json Unmarshal:%s", errMsg)
					return false, nil, err
				}
				errMsg = data["outTimeMsg"].(string)
				log.Error("PasswordExpiration:%s", errMsg)
				return false, nil, errors.New(errMsg)
			}
		}
	}

	// 用户到期时间
	if user.UserExpiration != "" {
		arr := strings.Split(user.UserExpiration, " ")
		if len(arr) > 0 {
			t, err := time.Parse("2006-01-02", arr[0])
			if err != nil {
				return false, nil, err
			}
			if t.Before(time.Now()) {
				errMsg := "User account expiration" // 用户账户到期
				log.Error("UserExpiration:%s", errMsg)
				return false, nil, errors.New(errMsg)
			}
		}
	}

	return true, user, nil
}

func XormIsExistUser(accid string) (bool, error) {
	log.Info("XormIsExistUser processing... ")

	exist, err := xEngine.Table("user").
		Where("account_id=?", accid).
		Exist()
	if err != nil {
		log.Error("Failed to exist user:", err)

		return false, err
	}

	return exist, nil
}

func XormGetConfig(moduleName, configTag string) (map[string]any, error) {
	result, err := DbClient.XEngine.QueryInterface("select * from config where module_name=? and config_tag=?", moduleName, configTag)
	if err != nil {
		log.Error("Failed to get config:", err)
		return nil, err
	}
	if len(result) > 0 {
		return result[0], nil
	}
	return map[string]any{}, nil
}

func XormGetConfigValue(moduleName, configTag string) (string, error) {
	var value string
	_, err := xEngine.Table("config").
		Where("module_name=? and config_tag=?", moduleName, configTag).
		Cols("value").
		Get(&value)
	if err != nil {
		log.Error("Failed to get config:", err)
		return "", err
	}
	return value, nil
}

type Session struct {
	Id          int          `json:"id" xorm:"pk 'id' autoincr"`
	AccountId   string       `json:"accountId" xorm:"account_id"`
	Name        string       `json:"name" xorm:"name"`
	Host        string       `json:"host" xorm:"host"`
	AccessToken string       `json:"accessToken" xorm:"access_token"`
	Expires     uint32       `json:"expires" xorm:"expires"`
	Status      string       `json:"status" xorm:"status"`
	LoginTime   string       `json:"loginTime" xorm:"-"`
	ShakeTime   sql.NullTime `son:"shakeTime" xorm:"shake_time"`
	LogoutTime  sql.NullTime `json:"logoutTime" xorm:"logout_time"`
}

// XormInsertSession create session
func XormInsertSession(name, host, token string, expires uint32, sessionFlag string) (int64, error) {
	log.Info("XormInsertSession processing... ")

	var affected int64 = 0
	var err error = nil
	currentTime := time.Now()
	timeValue := currentTime.Local()
	nullTime := sql.NullTime{Valid: true, Time: timeValue}
	value, err := XormGetConfigValue("Security", "sessionExpires")
	if err != nil {
		return affected, err
	}
	if value != "" {
		intValue, _ := strconv.Atoi(value)
		expires = uint32(intValue)
		log.Debugf("intValue=%d, expires=%d", intValue, expires)
	}

	session := Session{AccountId: name,
		Name: name, Host: host, AccessToken: token,
		Status: "online", Expires: expires,
		ShakeTime: nullTime,
	}

	//session.ShakeTime.Time
	xSession := xEngine.NewSession()
	defer xSession.Close()
	if strings.ToLower(sessionFlag) == "multiple" {
		exist, err := xEngine.Table("session").Where("status = 'online' and account_id = ? and host = ?", name, host).Exist()
		if err != nil {
			return affected, err
		}
		if exist == true {
			affected, err = xSession.Table("session").Where("account_id = ? and host = ?", name, host).Update(session)
		} else {
			affected, err = xSession.InsertOne(session)
		}
	} else { // single session for a user
		exist, err := xEngine.Table("session").Where("status = 'online' and account_id = ?", name).Exist()
		if err != nil {
			return affected, err
		}
		if exist == true {
			// todo...
			err := errors.New("user is logged in")
			return -1, err
		} else {
			affected, err = xSession.InsertOne(session)
		}
	}
	xSession.Commit()
	return affected, err
}

// XormUpdateSession update session
func XormLogoutUpdateSession(token string) (Session, error) {
	log.Info("XormLogoutUpdateSession processing... ")

	session := Session{Status: "offline", AccessToken: token}
	session.LogoutTime.Valid = true
	session.LogoutTime.Time = time.Now()

	xSession := xEngine.NewSession()
	defer xSession.Close()
	_, err := xSession.Table("session").Where("access_token = ?", token).Update(session)
	xSession.Commit()
	// 查询记录返回
	if err == nil {
		session := Session{}
		_, err = xSession.Table("session").Where("access_token = ?", token).Get(&session)
		return session, err
	}
	return session, err
}

// XormUpdateSessionShakeTime create session
func XormUpdateSessionShakeTime(token string) (Session, error) {
	log.Debug("XormUpdateSessionShakeTime processing... ")

	session := Session{AccessToken: token}
	session.ShakeTime.Valid = true
	session.ShakeTime.Time = time.Now()
	xSession := xEngine.NewSession()
	defer xSession.Close()
	_, err := xSession.Table("session").Where("access_token = ?", token).Update(session)
	xSession.Commit()
	// 查询记录返回
	if err == nil {
		session := Session{}
		_, err = xSession.Table("session").Where("access_token = ?", token).Get(&session)
		return session, err
	}
	return session, err
}

func XormExistValidToken(token string, expires uint32) bool {
	log.Info("XormExistValidToken processing... ")

	exist, err := xEngine.Table("session").
		Where("status = 'online' and access_token = ? and DATE_ADD(shake_time, INTERVAL expires SECOND) > NOW()", token).
		Exist()
	if err != nil {
		return false
	}

	return exist
}

/*
	type NorthboundPm struct {
		Id         int    `json:"id" xorm:"pk 'id' autoincr"`
		Date       string `json:"date" xorm:"date"`
		Index      int    `json:"index"`
		StartTime  string `json:"startTime" xorm:"start_time"`
		TimeZone   string `json:"timeZone" xorm:"time_zone"`
		NEName     string `json:"neName" xorm:"ne_name"`
		PmVersion  string `json:"pmVersion" xorm:"pm_version"`
		Period     string `json:"period" xorm:"pevalue"
		RmUid      string `json:"rmUid" xorm:"rm_uid"`
		NEType     string `json:"neType" xorm:"ne_type"`
		Dn         string `json:"neType" xorm:"ne_type"`
		ObjectType string `json:"objectType" xorm:"object_type"`
		PmName     string `json:"pmName" xorm:"pm_name"`
		PmExt      string `json:"pmExt" xorm:"pm_ext"`
		Value      int    `json:"value" xorm:"value"`
		Timestamp  string `json:"timestamp" xorm:"timestamp"`
	}
*/
type NorthboundPm struct {
	Id        int    `json:"-" xorm:"pk 'id' autoincr"`
	Date      string `json:"Date" xorm:"date"`
	Index     int    `json:"Index" xorm:"index"` // 1天中测量时间粒度(如15分钟)的切片索引: 0~95
	Timestamp string `json:"-" xorm:"-"`
	NeName    string `json:"NeName" xorm:"ne_name"` // UserLabel
	RmUID     string `json:"RmUID" xorm:"rm_uid"`
	NeType    string `json:"NeType" xorm:"ne_type"`       // 网元类型
	PmVersion string `json:"PmVersion" xorm:"pm_version"` // 性能数据版本号
	Dn        string `json:"Dn"  xorm:"dn"`               // (???)网元标识, 如:RJN-CMZJ-TZ,SubNetwork=5GC88,ManagedElement=SMF53456,SmfFunction=53456
	Period    string `json:"Period" xorm:"period"`        // 测量时间粒度选项：5/15/30/60
	TimeZone  string `json:"TimeZone"  xorm:"time_zone"`
	StartTime string `json:"StartTime" xorm:"start_time"`

	Datas []struct {
		ObjectType string `json:"ObjectType" xorm:"object_type"` // 网络资源类别名称, Pm指标项列表中为空间粒度 如：SmfFunction
		PmDatas    []struct {
			PmName   string `json:"KPIID" xorm:"pm_name"` // 指标项, 如： SMF.AttCreatePduSession._Dnn
			SubDatas []struct {
				SN string `json:"Name" xorm:"sn"` // 单个的写"Total", 或者指标项有多个测量项，如Dnn的名称写对应的Dnn"cmnet"/"ims"
				SV int64  `json:"Value" xorm:"sv"`
			} `json:"KPIValues" xorm:"sub_datas"`
		} `json:"KPIs"  xorm:"pm_datas"`
	} `json:"Datas" xorm:"datas"`
}

type Alarm struct {
	AlarmSeq          int    `json:"alarmSeq"`
	AlarmId           string `json:"alarmId" xorm:"alarm_id"`
	NeId              string `json:"neId"`
	AlarmCode         int    `json:"alarmCode"`
	AlarmTitle        string `json:"alarmTitle"`
	EventTime         string `json:"eventTime"`
	AlarmType         string `json:"alarmType"`
	OrigSeverity      string `json:"origSeverity"`
	PVFlag            string `json:"pvFlag" xorm:"pv_flag"`
	NeName            string `json:"neName"`
	NeType            string `json:"neType"`
	ObjectUid         string `json:"objectUid" xorm:"object_uid"`
	ObjectName        string `json:"objectName" xorm:"object_name"`
	ObjectType        string `json:"objectType" xorm:"object_type"`
	LocationInfo      string `json:"locationInfo"`
	Province          string `json:"province"`
	AlarmStatus       int    `json:"alarmStatus"`
	SpecificProblem   string `json:"specificProblem"`
	SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"`
	AddInfo           string `json:"addInfo"`

	//	AckState  int    `json:"ackState" xorm:"-"`
	//	AckTime   string `json:"ackTime" xorm:"-"`
	ClearType int    `json:"clearType" xorm:"-"` // 0: Unclear, 1: Auto clear, 2: Manual clear
	ClearTime string `json:"clearTime" xorm:"-"`
}

func XormGetAlarmByAlarmId(alarmId string, alarms *[]Alarm) (*[]Alarm, error) {
	log.Debug("XormGetAlarmByAlarmId processing... ")

	alarm := new(Alarm)
	rows, err := xEngine.Table("alarm").Where("alarm_id=?", alarmId).Rows(alarm)
	if err != nil {
		log.Error("Failed to get table alarm from database:", err)
		return nil, err
	}

	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(alarm)
		if err != nil {
			log.Error("Failed to get table alarm from database:", err)
			return nil, err
		}
		*alarms = append(*alarms, *alarm)
	}

	log.Trace("alarms:", alarms)
	return alarms, nil
}

func XormSQLGetStringValue(querySQL string) (string, error) {
	log.Debug("XormSQLGetStringValue processing... ")

	row := make(map[string]interface{})
	_, err := xEngine.SQL(querySQL).Get(&row)
	if err != nil {
		log.Errorf("Failed to get by SQL=%s:%v", querySQL, err)
		return "", err
	}

	for _, v := range row {
		return fmt.Sprintf("%v", v), nil
	}

	return "", nil
}

func XormGetSingleCol(table, col, where string) (string, error) {
	log.Debug("XormGetSingleCol processing... ")

	row := make(map[string]interface{})
	_, err := xEngine.Table(table).Where(where).Cols(col).Get(&row)
	if err != nil {
		log.Errorf("Failed to get %s from table %s:%v", col, table, err)
		return "", err
	}

	for _, v := range row {
		return fmt.Sprintf("%v", v), nil
	}

	return "", nil
}

func XormGetSingleColStringArrayByIn(table, col, incol string, conditions []string, cols *[]string) error {
	log.Debug("XormGetSingleColStringArrayByIn processing... ")

	err := xEngine.Table(table).In(incol, conditions).Cols(col).Distinct().Find(cols)
	if err != nil {
		log.Errorf("Failed to get %s from table %s:%v", col, table, err)
		return err
	}
	return nil
}

func XormGetColStringArrayByWhere(table, coln, where string, colv *[]string) error {
	log.Debug("XormGetColStringArrayByWhere processing... ")

	_, err := xEngine.Table(table).Where(where).Cols(coln).Get(colv)
	if err != nil {
		log.Errorf("Failed to Get %s from table %s:%v", coln, table, err)
		return err
	}
	return nil
}

func XormFindColStringArrayByWhere(table, col, where string, cols *[]string) error {
	log.Debug("XormFindColStringArrayByWhere processing... ")

	err := xEngine.Table(table).Where(where).Cols(col).Distinct().Find(cols)
	if err != nil {
		log.Errorf("Failed to Find %s from table %s:%v", col, table, err)
		return err
	}
	return nil
}

func XormGetSingleColStringByWhere(table, col, where string) (string, error) {
	log.Info("XormFindSingleColStringByWhere processing... ")

	var colv string
	_, err := xEngine.Table(table).Where(where).Cols(col).Get(&colv)
	if err != nil {
		log.Errorf("Failed to Find %s from table %s:%v", col, table, err)
		return colv, err
	}
	return colv, nil
}

func XormGetSingleColStringArrayByID(table, col string, id int, cols *[]string) error {
	log.Debug("XormGetSingleColStringArrayByID processing... ")

	err := xEngine.Table(table).ID(id).Cols(col).Find(cols)
	if err != nil {
		log.Errorf("Failed to Find %s from table %s:%v", col, table, err)
		return err
	}
	return nil
}

func XormGetStringValue(table, col string, id int) (string, error) {
	log.Debug("XormGetStringValue processing... ")

	row := make(map[string]interface{})
	_, err := xEngine.ID(id).Table(table).Cols(col).Get(&row)
	if err != nil {
		log.Errorf("Failed to get %s from table %s:%v", col, table, err)
		return "", err
	}

	for _, v := range row {
		return fmt.Sprintf("%v", v), nil
	}

	return "", nil
}

type NeBackup struct {
	Id         int    `json:"id" xorm:"pk 'id' autoincr"`
	NeType     string `json:"neType" xorm:"ne_type"`
	NeId       string `json:"neId" xorm:"ne_id"`
	FileName   string `json:"neName" xorm:"file_name"`
	Path       string `json:"path"`
	Md5Sum     string `json:"md5Sum" xorm:"md5_sum"`
	CreateTime string `json:"createTime" xorm:"-" `
}

// XormInsertSession create session
func XormInsertTableOne(tableName string, tbInfo interface{}) (int64, error) {
	log.Debug("XormInsertTableOne processing... ")

	var affected int64 = 0
	var err error = nil

	xSession := xEngine.NewSession()
	defer xSession.Close()
	affected, err = xSession.Table(tableName).InsertOne(tbInfo)
	xSession.Commit()
	return affected, err
}

// XormExistTableOne create session
func XormExistTableOne(tableName string, where string) (bool, error) {
	log.Debug("XormExistTableOne processing... ")

	has, err := xEngine.Table(tableName).Where(where).Exist()

	return has, err
}

func XormGetTableRows(tableName string, where string, tbInfo *[]interface{}) (*[]interface{}, error) {
	log.Debug("XormGetTableRows processing... ")

	row := make(map[string]interface{})
	rows, err := xEngine.Table(tableName).Where(where).Rows(row)
	if err != nil {
		log.Errorf("Failed to Rows table %s from database: %v", tableName, err)
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(row)
		if err != nil {
			log.Errorf("Failed to Scan table %s from database: %v", tableName, err)
			return nil, err
		}
		*tbInfo = append(*tbInfo, row)
	}
	log.Trace("tbInfo:", tbInfo)
	return tbInfo, nil
}

type MeasureThreshold struct {
	Id           int      `json:"id" xorm:"pk 'id' autoincr"`
	NeType       string   `json:"neType" xorm:"ne_type"`
	KpiSet       []string `json:"kpiSet" xorm:"kpi_set"`
	Threshold    int64    `json:"threshold"`
	Status       string   `json:"md5Sum" xorm:"md5_sum"`
	OrigSeverity string   `json:"createTime" xorm:"orig_severity"`
	AlarmId      string   `json:"alarmId" xorm:"alarm_id"`
}

type NeSoftware struct {
	Id       int    `json:"id" xorm:"pk 'id' autoincr"`
	NeType   string `json:"neType" xorm:"ne_type"`
	FileName string `json:"neName" xorm:"file_name"`
	Path     string `json:"path"`
	Version  string `json:"version"`
	Md5Sum   string `json:"md5Sum" xorm:"md5_sum"`
	Comment  string `json:"comment"`
	//	Status     string `json:"status"`
	UpdateTime string `json:"createTime" xorm:"-" `
}

type NeVersion struct {
	Id         int    `json:"id" xorm:"pk 'id' autoincr"`
	NeType     string `json:"neType" xorm:"ne_type"`
	NeId       string `json:"neId" xorm:"ne_id"`
	Version    string `json:"version"`
	FilePath   string `json:"filePath" xorm:"file_path"`
	NewVersion string `json:"newVersion" xorm:"new_version"`
	NewFile    string `json:"newFile" xorm:"new_file"`
	PreVersion string `json:"preVersion" xorm:"pre_version"`
	PreFile    string `json:"preFile" xorm:"pre_file"`
	Status     string `json:"status"`
	UpdateTime string `json:"createTime" xorm:"-" `
}

func XormGetDataBySQL(sql string) (*[]map[string]string, error) {
	log.Debug("XormGetDataBySQL processing... ")

	rows := make([]map[string]string, 0)
	rows, err := DbClient.XEngine.QueryString(sql)
	if err != nil {
		log.Error("Failed to QueryString:", err)
		return nil, err
	}

	return &rows, nil
}

func XormDeleteDataByWhere(where, table string) (int64, error) {
	log.Debug("XormDeleteDataByWhere processing... ")

	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.Table(table).Where(where).Delete()
	if err != nil {
		log.Error("Failed to Delete:", err)
		return 0, err
	}
	xSession.Commit()

	return affected, nil
}

func XormDeleteDataById(id int, table string) (int64, error) {
	log.Debug("XormDeleteDataByWhere processing... ")

	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.Table(table).ID(id).Delete()
	if err != nil {
		log.Error("Failed to Delete:", err)
		return 0, err
	}
	xSession.Commit()

	return affected, nil
}

type ColOutput struct {
	Name    string   `json:"name"`
	Display string   `json:"display"`
	Length  int      `json:"length"`
	Alias   []string `json:"Alias"`
}

type ColInput struct {
	Name   string `json:"name"`
	Alias  string `json:"Alias"`
	Type   string `json:"type"`
	Length int    `json:"length"`
	Value  any    `json:"value"`
}

type MmlInput struct {
	BodyFmt  string     `json:"bodyFmt"`
	BodyKey  string     `json:"bodyKey"`
	CallFunc string     `json:"callFunc"`
	Cols     []ColInput `json:"cols"`
}

type MmlOutput struct {
	RetFmt      string      `json:"retFmt"`
	RetMsg      string      `json:"retMsg"`
	ErrMsg      string      `json:"errMsg"`
	Title       string      `json:"title"`
	SingleList  bool        `json:"singleList"`
	SepSpaceNum int         `json:"sepSpaceNum"`
	AlignmentM  string      `json:"alignmentM"`
	AlignmentSN string      `json:"alignmentSN"`
	AlignmentSV string      `json:"alignmentSV"`
	Cols        []ColOutput `json:"cols"`
	End         string      `json:"end"`
}

type MmlHttpMap struct {
	ID        int    `json:"-" xorm:"id"`
	NeType    string `json:"neType" xorm:"ne_type"`
	Operation string `json:"operation"`
	Object    string `json:"object"`
	Method    string `json:"method"`
	URI       string `json:"uri" xorm:"uri"`
	ExtUri    string `json:"extUri"`
	ParamTag  string `json:"paramTag"`
	Params    string `json:"params"`
	Input     string `json:"input"`
	Output    string `json:"output"`
}

func XormGetMmlHttpMap(table, where string) (*MmlHttpMap, error) {
	mmlMap := new(MmlHttpMap)
	_, err := DbClient.XEngine.Table(table).Where(where).Get(mmlMap)
	if err != nil {
		log.Error("Failed to Get:", err)
		return nil, err
	}
	return mmlMap, nil
}

type MmlCommand struct {
	ID         int    `json:"-" xorm:"id"`
	NeType     string `json:"neType" xorm:"ne_type"`
	Category   string `json:"category"`
	CatDisplay string `json:"catDisplay"`
	Operation  string `json:"operation"`
	Object     string `json:"object" xorm:"object"`
	MmlDisplay string `json:"mmlDisplay"`
	ParamJson  []struct {
		Name     string `json:"name"`
		Alias    string `json:"alias"`
		Type     string `json:"type"`
		Optional string `json:"optional"`
		Apostr   string `json:"apostr"`
		Loc      string `json:"loc"`
		Filter   string `json:"filter"`
		Display  string `json:"display"`
		Comment  string `json:"comment"`
	} `json:"paramJson"`
}

func XormGetMmlCommand(table, where string) (*MmlCommand, error) {
	mmlCmd := new(MmlCommand)
	_, err := DbClient.XEngine.Table(table).Where(where).Get(mmlCmd)
	if err != nil {
		log.Error("Failed to Get:", err)
		return nil, err
	}
	return mmlCmd, nil
}

type AlarmOMCConfig struct {
	ID         int    `json:"-" xorm:"id"`
	ModuleName string `json:"moduleName"`
	ConfigTag  string `json:"configTag"`
	Value      string `json:"value"`
	ValueJson  string `json:"valueJson"`
}

type ValueJson struct {
	AlarmStatus  string `json:"alarm_status"`
	AlarmType    string `json:"alarm_type"`
	OrigSeverity string `json:"orig_severity"`
	AckUser      string `json:"ack_user"`
}

type AlarmForwardToUsers struct {
	Interface string   `json:"interface"`
	ToUser    []string `json:"to_user"`
}

func XormGetAAConfig() (*ValueJson, error) {
	aaConfig := new(AlarmOMCConfig)
	_, err := DbClient.XEngine.Table("config").
		Where("module_name=? and config_tag=?", "Alarm", "autoAlarmAck").
		Cols("value", "value_json").
		Get(aaConfig)
	if err != nil {
		log.Error("Failed to Get:", err)
		return nil, err
	}
	log.Debug("aaConfig:", aaConfig)
	valueJson := new(ValueJson)
	err = json.Unmarshal([]byte(aaConfig.ValueJson), valueJson)
	if err != nil {
		log.Error("Failed to Unmarshal:", err)
		return nil, err
	}
	log.Debug("valueJson:", valueJson)
	return valueJson, nil
}

func XormGetAlarmForward(interfaceName string) (*[]string, error) {
	alarmForwardConfig := new(AlarmOMCConfig)
	_, err := DbClient.XEngine.Table("config").
		Where("module_name=? and config_tag=?", "Alarm", "forwardAlarm").
		Cols("value", "value_json").
		Get(alarmForwardConfig)
	if err != nil {
		log.Error("Failed to Get:", err)
		return nil, err
	}
	log.Debug("alarmForwardConfig:", alarmForwardConfig)
	alarmForwardToUsers := new([]AlarmForwardToUsers)
	err = json.Unmarshal([]byte(alarmForwardConfig.ValueJson), alarmForwardToUsers)
	if err != nil {
		log.Error("Failed to Unmarshal:", err)
		return nil, err
	}
	log.Debug("alarmForwardToUsers:", alarmForwardToUsers)
	for _, a := range *alarmForwardToUsers {
		if a.Interface == interfaceName {
			return &(a.ToUser), nil
		}
	}
	return nil, nil
}

type AlarmForwardLog struct {
	ID         int    `json:"-" xorm:"pk 'id' autoincr"`
	NeType     string `json:"neType" xorm:"ne_type"`
	NeID       string `json:"neID" xorm:"ne_id"`
	AlarmID    string `json:"alarmID" xorm:"alarm_id"`
	AlarmTitle string `json:"alarmTitle" xorm:"alarm_title"`
	AlarmSeq   int    `json:"alarmSeq" xorm:"alarm_seq"`
	EventTime  string `json:"eventTime" xorm:"event_time"`
	ToUser     string `json:"toUser" xorm:"to_user"`
	OperResult string `json:"operResult" xorm:"oper_result"`
	LogTime    string `json:"-" xorm:"-"`
}

func XormInsertAlarmForwardLog(logData *AlarmForwardLog) (int64, error) {
	log.Debug("XormInsertAlarmForwardLog processing... ")

	xSession := xEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.Insert(logData)
	xSession.Commit()

	return affected, err
}

type SystemLog struct {
	ID          int    `json:"-" xorm:"pk 'id' autoincr"`
	UserName    string `json:"user_name" xorm:"user_name"`
	ProcessName string `json:"process_name" xorm:"process_name"`
	ProcessID   int32  `json:"process_id" xorm:"process_id"`
	Operation   string `json:"operation" xorm:"operation"`
	StartTime   string `json:"start_time" `
	LogTime     string `json:"-" xorm:"-"`
}

func XormInsertSystemLog(logData *SystemLog) (int64, error) {
	log.Info("XormInsertSystemLog processing... ")

	xSession := xEngine.NewSession()
	defer xSession.Close()
	affected, err := xSession.Insert(logData)
	xSession.Commit()

	return affected, err
}

type permission struct {
	ID             int    `json:"-" xorm:"pk 'id' autoincr"`
	PermissionName string `json:"permissionName"`
	Method         string `json:"method"`
	Element        string `json:"element"`
	Object         string `json:"object"`
}

func IsPermissionAllowed(token, method, module, dbname, tbname, pack string) (bool, error) {
	log.Info("IsPermissionAllowed processing... ")

	exist, err := xEngine.Table("permission").
		Join("INNER", "role_permission", "permission.permission_name = role_permission.p_name").
		Join("INNER", "user_role", "role_permission.r_name = user_role.r_name").
		Join("INNER", "session", "user_role.u_name = session.account_id and session.access_token=?", token).
		Where("method in ('*',?) and module in ('*',?) and management in ('*',?) and element in ('*',?) and object in ('*',?)", method, pack, module, dbname, tbname).
		Exist()
	if err != nil {
		return false, err
	}

	return exist, nil
}

type NeLicense struct {
	NeType         string `json:"neType" xorm:"ne_type"`
	NeID           string `json:"neID" xorm:"ne_id"`
	SerialNo       string `json:"serialNo" xorm:"serial_no"`
	Capcity        int    `json:"capcity" xorm:"capcity"`
	Used           int    `json:"used" xorm:"used"`
	FeatureEnabled string `json:"featureEnabled" xorm:"feature_enabled"`
	ExpirationDate string `json:"expirationDate" xorm:"expiration_date"`
	Status         string `json:"status" xorm:"status"`
	Path           string `json:"path" xorm:"path"`
	FileName       string `json:"file_name" xorm:"file_name"`
	Comment        string `json:"comment" xorm:"comment"`
	CreatedAt      string `json:"createdAt" xorm:"-"`
	UpdatedAt      string `json:"updatedAt" xorm:"-"`
	DeletedAt      string `json:"deletedAt" xorm:"-"`
}

func XormAdjustmentNeLicense(neType, neID string, value int) (int64, error) {
	//neLicense := NeLicense{NeType: neType, NeID: neID, Capability: value}
	// session.LogoutTime.Valid = true
	// session.LogoutTime.Time = time.Now()
	res, err := xEngine.Exec("update ne_license set capcity=capcity+? where IFNULL(ne_type, '')=? and IFNULL(ne_id, '')=?", value, neType, neID)
	// defer xSession.Close()

	//affected, err := xSession.Table("ne_license").Where("ne_type=? and ne_id=?", neType, neID).Update(&neLicense)

	// //affected, err := xSession.Table("ne_license").SQL("ne_tye=? and ne_id=?", neType, neID).Update(session)
	// err := xSession.SQL("update ne_license set capability=capability+? where ne_type=? and ne_id=?", value, neType, neID)
	//xSession.Commit()
	affected, err := res.RowsAffected()
	return affected, err
}

func XormUpdateNeLicense(neType, neID string, capcity int) (int64, error) {
	var err error
	var res sql.Result
	if neType != "" && neID != "" {
		res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=? and ne_id=?", capcity, neType, neID)
	} else if neType != "" && neID == "" {
		res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=?", capcity, neType)
	} else if neType == "" && neID != "" {
		res, err = xEngine.Exec("update ne_license set capcity=? where ne_id=?", capcity, neID)
	} else {
		res, err = xEngine.Exec("update ne_license set capcity=?", capcity)
	}

	affected, err := res.RowsAffected()
	return affected, err
}

type NorthboundCm struct {
	ID            int    `json:"-" xorm:"pk '-' autoincr"`
	Timestamp     string `json:"timestamp" xorm:"timestamp"`
	TimeZone      string `json:"timeZone" xorm:"time_zone"`
	VendorName    string `json:"vendorName" xorm:"vendor_name"`
	NeType        string `json:"neType" xorm:"ne_type"`
	CmVersion     string `json:"cmVersion" xorm:"cm_version"`
	RmUID         string `json:"rmUID" xorm:"rm_uid"`
	NeID          string `json:"neID" xorm:"ne_id"`
	UserLabel     string `json:"userLabel" xorm:"user_label"`
	ObjectType    string `json:"objectType" xorm:"object_type"`
	PvFlag        string `json:"pvFlag" xorm:"pv_flag"`
	VMID          string `json:"vmID" xorm:"vm_id"`
	VnfInstanceID string `json:"vnf_instance_id"`
	ValueJSON     string `json:"valueJson" xorm:"value_json"`
	Status        string `json:"status" xorm:"status"`
}

func XormGetNorthboundCm(neType string, cmResults *[]NorthboundCm) error {
	log.Info("XormGetNorthboundCm processing... ")

	cmResult := new(NorthboundCm)
	rows, err := xEngine.Table("northbound_cm").
		Distinct("object_type").
		Where("`ne_type` = ?", neType).
		Desc("timestamp").
		Cols("*").
		Rows(cmResult)
	if err != nil {
		log.Error("Failed to get table northbound_cm:", err)
		return err
	}
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(cmResult)
		if err != nil {
			log.Error("Failed to get table northbound_cm:", err)
			return err
		}
		*cmResults = append(*cmResults, *cmResult)
	}
	return nil
}

func XormGetNorthboundCmLatestObject(neType, neID, objectType string) (*NorthboundCm, error) {
	log.Info("XormGetNorthboundCmLatestObject processing... ")

	cmResult := new(NorthboundCm)
	_, err := xEngine.Table("northbound_cm").
		Where("`ne_type`=? and `ne_id`=? and `object_type`=?", neType, neID, objectType).
		Desc("timestamp").
		Cols("*").
		Limit(1).
		Get(cmResult)
	if err != nil {
		log.Error("Failed to get table northbound_cm:", err)
		return nil, err
	}

	return cmResult, nil
}

type TraceData struct {
	ID        int    `json:"-" xorm:"pk 'id' autoincr"`
	TaskID    int    `json:"taskID" xorm:"task_id"`
	Imsi      string `json:"imsi" xorm:"imsi"`
	Msisdn    string `json:"msisdn" xorm:"msisdn"`
	SrcAddr   string `json:"srcAddr" xorm:"src_addr"`
	DstAddr   string `json:"dstAddr" xorm:"dst_addr"`
	IfType    int    `json:"ifType" xorm:"if_type"`
	MsgType   int    `json:"msgType" xorm:"msg_type"`
	MsgDirect int    `json:"msgDirect" xorm:"msg_direct"`
	Length    int    `json:"length" xorm:"length"`
	Timestamp int64  `json:"timestamp" xorm:"timestamp"`
	RawMsg    []byte `json:"rawMsg" xorm:"raw_msg"`
	DecMsg    string `json:"decMsg" xorm:"dec_msg"`
}

func XormGetTraceData(id int) (*TraceData, error) {
	result := new(TraceData)
	_, err := xEngine.Table("trace_data").
		Where("id=?", id).
		Get(result)
	if err != nil {
		log.Error("Failed to get table trace_data:", err)
		return nil, err
	}

	return result, nil
}

func XormUpdateTraceData(id int, data *TraceData) (int64, error) {
	affected, err := xEngine.Table("trace_data").
		Where("id=?", id).
		Update(data)
	if err != nil {
		log.Error("Failed to update table trace_data:", err)
		return 0, err
	}

	return affected, nil
}

func XormInsertTraceData(data *TraceData) (int64, error) {
	affected, err := xEngine.Table("trace_data").
		InsertOne(data)
	if err != nil {
		log.Error("Failed to insert table trace_data:", err)
		return 0, err
	}

	return affected, nil
}

func XormDeleteTraceData(id int) (int64, error) {
	affected, err := xEngine.Table("trace_data").
		Where("id=?", id).
		Delete()
	if err != nil {
		log.Error("Failed to delete table trace_data:", err)
		return 0, err
	}

	return affected, nil
}

func XormGetTraceRawMsg(id int) (int64, []byte, error) {
	var rawMsg []byte
	var timestamp int64
	_, err := xEngine.Table("trace_data").
		Where("id=?", id).
		Cols("timestamp", "raw_msg").
		Get(&timestamp, &rawMsg)
	if err != nil {
		log.Error("Failed to get table trace_data:", err)
		return timestamp, rawMsg, err
	}

	return timestamp, rawMsg, nil
}

func XormGetNEStateInfo(neType, neID string) (string, string, error) {
	SN := "-"
	Version := "-"
	_, err := xEngine.Table("ne_state").
		Where("ne_type=? and ne_id=?", neType, neID).
		Desc("timestamp").
		Cols("serial_num", "version").
		Limit(1).
		Get(&SN, &Version)
	return SN, Version, err
}

type NeState struct {
	Id         int    `json:"id" xorm:"pk 'id' autoincr"`
	NeType     string `json:"neType" xorm:"ne_type"`
	NeId       string `json:"neId" xorm:"ne_id"`
	Version    string `json:"version" xorm:"column 'version' VARCHAR(16)"`
	Capability uint32 `json:"capability" xorm:"capability"`
	SerialNum  string `json:"serialNum" xorm:"serial_num"`
	ExpiryDate string `json:"expiryDate" xorm:"expiry_date"`
	CpuUsage   string `json:"cpuUsage" xorm:"cpu_usage"`
	MemUsage   string `json:"memUsage" xorm:"mem_usage"`
	DiskSpace  string `json:"diskSpace" xorm:"disk_space"`
	Timestamp  string `json:"timestamp" xorm:"-" `
}

func XormInsertNeState(neState *NeState) (int64, error) {
	log.Debug("XormInsertNeState processing... ")

	var affected int64 = 0

	session := xEngine.NewSession()
	defer session.Close()
	affected, err := session.InsertOne(neState)
	if err != nil {
		return 0, err
	}
	err = session.Commit()
	if err != nil {
		return 0, err
	}
	return affected, err
}

type AlarmDefine struct {
	AlarmId           string `json:"alarmId" xorm:"alarm_id"`
	AlarmCode         int    `json:"alarmCode" xorm:"alarm_code"`
	AlarmTitle        string `json:"alarmTitle" xorm:"alarm_title"`
	NeType            string `json:"neType" xorm:"ne_type"`
	AlarmType         string `json:"alarmType" xorm:"alarm_type"`
	OrigSeverity      string `json:"origSeverity" xorm:"orig_severity"`
	ObjectUid         string `json:"objectUid" xorm:"object_uid"`
	ObjectName        string `json:"objectName" xorm:"object_name"`
	ObjectType        string `json:"objectType" xorm:"object_type"`
	LocationInfo      string `json:"locationInfo"`
	SpecificProblem   string `json:"specificProblem"`
	SpecificProblemId string `json:"specificProblemId" xorm:"specific_problem_id"`
	AddInfo           string `json:"addInfo" xorm:"add_info"`
	Threshold         int64  `json:"threshold" xorm:"threshold"`
	Status            string `json:"status" xorm:"status"`
}

func XormGetAlarmDefine(alarmCode string) (*AlarmDefine, error) {
	log.Debug("XormGetAlarmDefine processing... ")

	alarmDefine := new(AlarmDefine)
	_, err := xEngine.
		Where("alarm_code=? and status='Active'", alarmCode).
		Get(alarmDefine)
	if err != nil {
		log.Error("Failed to get table alarm_define from database:", err)
		return nil, err
	}

	return alarmDefine, nil
}
