package dbrest

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strings"
	"time"

	"be.ems/lib/core/utils/ctx"
	"be.ems/lib/dborm"
	"be.ems/lib/global"
	"be.ems/lib/log"
	"be.ems/lib/services"
	"be.ems/restagent/config"

	"github.com/gorilla/mux"
	"xorm.io/xorm"
)

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

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

var (
	// database management rest pattern， discard
	XormGetDataUri    = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
	XormSelectDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/select/{elementTypeValue}/{objectTypeValue}"
	XormInsertDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/insert/{elementTypeValue}/{objectTypeValue}"
	XormUpdateDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/update/{elementTypeValue}/{objectTypeValue}"
	XormDeleteDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/delete/{elementTypeValue}/{objectTypeValue}"

	CustomXormGetDataUri    = config.UriPrefix + "/databaseManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
	CustomXormSelectDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/select/{elementTypeValue}/{objectTypeValue}"
	CustomXormInsertDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/insert/{elementTypeValue}/{objectTypeValue}"
	CustomXormUpdateDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/update/{elementTypeValue}/{objectTypeValue}"
	CustomXormDeleteDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/delete/{elementTypeValue}/{objectTypeValue}"

	XormCommonUri   = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for internal
	XormDatabaseUri = config.DefaultUriPrefix + "/database/{apiVersion}/{elementTypeValue}/{objectTypeValue}"           // for crontask
	XormDataRestUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
	XormExtDataUri  = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external
	XormDataSQLUri  = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external

	CustomXormCommonUri  = config.UriPrefix + "/databaseManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for internal
	CustomXormExtDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}"     // for external
	CustomXormDataSQLUri = config.UriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}"     // for external

	// 查询数据库连接情况
	UriDbConnection       = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbConnection"
	CustomUriDbConnection = config.UriPrefix + "/dataManagement/{apiVersion}/dbConnection" // for external

	// 终结非法的数据库连接
	UriDbStop       = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbStop"
	CustomUriDbStop = config.UriPrefix + "/dataManagement/{apiVersion}/dbStop" // for external

)

var XEngine *xorm.Engine

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.SetLogger(&log.Elogger)
		DbClient.XEngine.ShowSQL(true)
	}
	XEngine = DbClient.XEngine

	return nil
}

func GetUriSQLArray(r *http.Request) []string {
	var sa []string
	vars := r.URL.Query()

	// 默认SQL
	if s, ok := vars["SQL"]; ok {
		for _, r := range s {
			if r != "" {
				sa = append(sa, r)
			}
		}
	}

	// 查询总数
	if totalSQL, ok := vars["totalSQL"]; ok {
		if totalSQL[0] != "" {
			sa = append(sa, totalSQL[0])
		}
	}
	// 查询列表
	if rowsSQL, ok := vars["rowsSQL"]; ok {
		if rowsSQL[0] != "" {
			sa = append(sa, rowsSQL[0])
		}
	}

	if len(sa) == 0 {
		log.Info("SQL is not exist")
		return nil
	}

	log.Debug("SQL array:", sa)
	return sa
}

// Get table name from SQL
func GetTableNameFromSQL(s string) string {
	ls := strings.ToLower(s)
	i1 := strings.Index(ls, "from")
	i2 := strings.Index(ls, "where")

	var ts string
	if i1 > 0 {
		if i2 > 0 && i2 > i1 {
			ts = ls[i1+4 : i2]
		}
		if i2 < 0 {
			ts = ls[i1+4:]
		}
	}

	tn := strings.Trim(ts, " ")
	log.Debug("i1:", i1, "i2:", i2, "tn:", tn)
	return tn
}

func GetTableName(sql string) string {
	ls := strings.ToLower(sql)

	re := regexp.MustCompile(`from\s+(\S+)`)
	matches := re.FindStringSubmatch(ls)
	if len(matches) < 2 {
		return ""
	}
	return matches[1]
}

func IsQuerySQL(s string) bool {
	ts := strings.Trim(strings.ToLower(s), " ")
	if strings.Index(ts, "select") != 0 {
		return false
	}
	return true
}

// xorm Get data from database
func ExtDatabaseExecSQL(w http.ResponseWriter, r *http.Request) {
	log.Debug("ExtDatabaseExecSQL processing... ")

	var sql []string
	var err error

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

	//vars := mux.Vars(r)
	//tblName := vars["objectTypeValue"]
	sql = GetUriSQLArray(r)
	// select as must, todo ...

	ls := services.ExtGetUriPageLimitString(r)

	//	data := make([]map[string]interface{}, 0)
	//	xormResponse := make([]map[string]interface{}, len(sql))
	var xormResponse XormResponse
	data := make([]map[string]interface{}, 0)
	for i, s := range sql {
		log.Tracef("SQL[%d]: %s", i, sql[i])

		//rows := make([]map[string]interface{}, 0)
		mapRows := make(map[string]interface{})

		if s != "" {
			//			err = XEngine.SQL(s).Find(&rows)
			// if IsQuerySQL(s) == false {
			// 	services.ResponseNotAcceptable406QuerySQLError(w)
			// 	return
			// }

			querySQL := s
			if i == (len(sql) - 1) {
				querySQL = querySQL + " " + ls
			}
			log.Debug("querySQL:", querySQL)
			rows, err := DbClient.XEngine.Exec(querySQL)
			if err != nil {
				log.Error("SQL failed:", err)
				services.ResponseInternalServerError500DatabaseOperationFailed(w)
				return
			}
			tableName := GetTableName(s)
			log.Debugf("s:%s tableName:%s", s, tableName)
			mapRows[tableName] = rows
			data = append(data, mapRows)
			log.Trace("data:", data)
		}
		i++
	}
	xormResponse.Data = data

	services.ResponseWithJson(w, http.StatusOK, xormResponse)
}

// xorm Get data from database
func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
	log.Debug("ExtDatabaseGetData processing... ")

	var sql []string
	token, err := services.CheckExtValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	pack := "dbrest"
	vars := mux.Vars(r)
	module := ""
	dbname := vars["elementTypeValue"]
	tbname := vars["objectTypeValue"]

	log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)

	// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
	// if err != nil {
	// 	log.Error("Failed to get permission:", err)
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }
	// if !exist {
	// 	log.Error("Not permission!")
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }

	sql = GetUriSQLArray(r)
	// select as must, todo ...
	if sql == nil {
		wc := services.GetUriLocString(r)
		if wc == "" {
			sql = append(sql, fmt.Sprintf("select * from %s", tbname))
		} else {
			sql = append(sql, fmt.Sprintf("select * from %s where %s", tbname, wc))
		}
	}

	ls := services.ExtGetUriPageLimitString(r)

	//	data := make([]map[string]interface{}, 0)
	//	xormResponse := make([]map[string]interface{}, len(sql))
	var xormResponse XormResponse
	data := make([]map[string]interface{}, 0)
	for i, s := range sql {
		log.Tracef("SQL[%d]: %s", i, sql[i])

		rows := make([]map[string]interface{}, 0)
		mapRows := make(map[string]interface{})

		if s != "" {
			//			err = XEngine.SQL(s).Find(&rows)
			if IsQuerySQL(s) == false {
				services.ResponseNotAcceptable406QuerySQLError(w)
				return
			}

			querySQL := s
			if i == (len(sql) - 1) {
				querySQL = querySQL + " " + ls
			}
			log.Debug("querySQL:", querySQL)
			rows, err = DbClient.XEngine.QueryInterface(querySQL)
			if err != nil {
				log.Error("SQL failed:", err)
				services.ResponseInternalServerError500DatabaseOperationFailed(w)
				return
			}
			tableName := GetTableName(s)
			log.Debugf("s:%s tableName:%s", s, tableName)
			mapRows[tableName] = rows
			data = append(data, mapRows)
			log.Trace("data:", data)
		}
		i++
	}
	xormResponse.Data = data

	services.ResponseWithJson(w, http.StatusOK, xormResponse)
}

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

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

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
	if err != nil {
		log.Error("io.ReadAll failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	vars := mux.Vars(r)
	module := ""
	dbname := vars["elementTypeValue"]
	tbname := vars["objectTypeValue"]
	pack := "dbrest"

	log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)

	// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
	// if err != nil {
	// 	log.Error("Failed to get permission:", err)
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }
	// if !exist {
	// 	log.Error("permission deny!")
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }

	log.Debug("Request body:", string(body), "dataObject:", tbname)
	insertData := make(map[string]interface{})
	_ = json.Unmarshal(body, &insertData)

	tn, sql := dborm.ConstructInsertSQL(tbname, insertData)
	log.Tracef("tn: %s sql :%s", tn, sql)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	var affected int64
	for _, s := range sql {
		res, err := xSession.Exec(s)
		if err != nil {
			log.Error("Insert failed:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
		n, _ := res.RowsAffected()
		affected = affected + n
	}
	xSession.Commit()
	//	affected, err := InsertDataWithJson(insertData)
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tn] = row
	//	xormResponse.Data = mapRow
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

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

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

	vars := mux.Vars(r)
	module := ""
	dbname := vars["elementTypeValue"]
	tbname := vars["objectTypeValue"]
	pack := "dbrest"

	log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)

	// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
	// if err != nil {
	// 	log.Error("Failed to get permission:", err)
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }
	// if !exist {
	// 	log.Error("Not permission!")
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	wc := services.GetUriLocString(r)

	log.Debug("Request body:", string(body), "Tablename:", tbname, "wc:", wc)
	updateData := make(map[string]interface{})
	_ = json.Unmarshal(body, &updateData)

	tn, sql := dborm.ConstructUpdateSQL(tbname, updateData, wc)
	log.Tracef("tn: %s sql :%s", tn, sql)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	var affected int64
	for _, s := range sql {
		res, err := xSession.Exec(s)
		if err != nil {
			log.Error("Update failed:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
		n, _ := res.RowsAffected()
		affected = affected + n
	}
	xSession.Commit()
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tn] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

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

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

	vars := mux.Vars(r)
	module := ""
	dbname := vars["elementTypeValue"]
	tbname := vars["objectTypeValue"]
	pack := "dbreset"

	log.Debugf("token:%s, method:%s, module:%, dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack)

	// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
	// if err != nil {
	// 	log.Error("Failed to get permission:", err)
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }
	// if !exist {
	// 	log.Error("Not permission!")
	// 	services.ResponseForbidden403NotPermission(w)
	// 	return
	// }

	wc := services.GetUriLocString(r)

	log.Debug("Table name:", tbname, "wc:", wc)

	sql := dborm.ConstructDeleteSQL(tbname, wc)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	res, err := xSession.Exec(sql)
	if err != nil {
		log.Error("Update failed, err:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}
	affected, _ := res.RowsAffected()
	xSession.Commit()
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow["data"] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

// xorm Get data from database
func DatabaseGetData(w http.ResponseWriter, r *http.Request) {
	log.Debug("DatabaseGetData processing... ")

	var sql []string
	var err error

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

	vars := mux.Vars(r)
	tblName := vars["objectTypeValue"]
	sql = GetUriSQLArray(r)
	// select as must, todo ...

	if sql == nil {
		wc := services.GetUriWhereString(r)
		if wc == "" {
			sql = append(sql, fmt.Sprintf("select * from %s", tblName))
		} else {
			sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc))
		}
	}

	ls := services.GetUriPageLimitString(r)

	//	data := make([]map[string]interface{}, 0)
	//	xormResponse := make([]map[string]interface{}, len(sql))
	var xormResponse XormResponse
	data := make([]map[string]interface{}, 0)
	for i, s := range sql {
		log.Tracef("SQL[%d]: %s", i, sql[i])

		rows := make([]map[string]interface{}, 0)
		mapRows := make(map[string]interface{})

		if s != "" {
			//			err = XEngine.SQL(s).Find(&rows)
			if IsQuerySQL(s) == false {
				services.ResponseNotAcceptable406QuerySQLError(w)
				return
			}

			querySQL := s
			if i == (len(sql) - 1) {
				querySQL = querySQL + " " + ls
			}
			log.Debug("querySQL:", querySQL)
			rows, err = DbClient.XEngine.QueryInterface(querySQL)
			if err != nil {
				log.Error("SQL failed:", err)
				services.ResponseInternalServerError500DatabaseOperationFailed(w)
				return
			}
			tableName := GetTableName(s)
			log.Debugf("s:%s tableName:%s", s, tableName)
			mapRows[tableName] = rows
			data = append(data, mapRows)
			log.Trace("data:", data)
		}
		i++
	}
	xormResponse.Data = data

	services.ResponseWithJson(w, http.StatusOK, xormResponse)
}

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

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
	if err != nil {
		log.Error("io.ReadAll failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	vars := mux.Vars(r)
	tableName := vars["objectTypeValue"]
	log.Debug("Request body:", string(body), "tableName:", tableName)
	insertData := make(map[string]interface{})
	_ = json.Unmarshal(body, &insertData)

	// 操作日志的IP
	if tableName == "operation_log" || tableName == "security_log" {
		ipAddr := strings.Split(r.RemoteAddr, ":")[0]
		s := insertData["data"].([]any)
		a := s[0].(map[string]any)
		a["op_ip"] = ipAddr
	} else if tableName == "mml_log" {
		ipAddr := strings.Split(r.RemoteAddr, ":")[0]
		s := insertData["data"].([]any)
		a := s[0].(map[string]any)
		a["ip"] = ipAddr
	}

	tn, sql := dborm.ConstructInsertSQL(tableName, insertData)
	log.Tracef("tn: %s sql :%s", tn, sql)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	var affected int64
	for _, s := range sql {
		res, err := xSession.Exec(s)
		if err != nil {
			log.Error("Insert failed:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
		n, _ := res.RowsAffected()
		affected = affected + n
	}
	xSession.Commit()
	//	affected, err := InsertDataWithJson(insertData)
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tn] = row
	//	xormResponse.Data = mapRow
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

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

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	vars := mux.Vars(r)
	tblName := vars["objectTypeValue"]
	wc := services.GetUriWhereString(r)

	log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc)
	updateData := make(map[string]interface{})
	_ = json.Unmarshal(body, &updateData)

	tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc)
	log.Tracef("tn: %s sql :%s", tn, sql)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	var affected int64
	for _, s := range sql {
		res, err := xSession.Exec(s)
		if err != nil {
			log.Error("Update failed:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
		n, _ := res.RowsAffected()
		affected = affected + n
	}
	xSession.Commit()
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tn] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

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

	vars := mux.Vars(r)
	tblName := vars["objectTypeValue"]
	wc := services.GetUriWhereString(r)

	log.Debug("Table name:", tblName, "wc:", wc)

	sql := dborm.ConstructDeleteSQL(tblName, wc)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	res, err := xSession.Exec(sql)
	if err != nil {
		log.Error("Update failed, err:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}
	affected, _ := res.RowsAffected()
	xSession.Commit()
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow["data"] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

// 连接用户实例
func DbConnection(w http.ResponseWriter, r *http.Request) {
	if dborm.DbClient.XEngine == nil {
		services.ResponseErrorWithJson(w, 400, "无连接")
	}
	// 查询实例
	result, err := dborm.DbClient.XEngine.QueryString("SHOW PROCESSLIST;")
	if err != nil {
		services.ResponseErrorWithJson(w, 500, err.Error())
	}
	filterData := []map[string]string{}
	for _, r := range result {
		if r["User"] != "system user" {
			filterData = append(filterData, r)
		}
	}
	// Sleep：连接处于空闲状态，没有执行任何操作。
	// Query：连接正在执行一个查询语句。
	// Execute：连接正在执行一个准备好的 SQL 语句。
	// Connect：连接正在建立但尚未完成。
	services.ResponseWithJson(w, 200, filterData)
}

// 关闭数据库连接
func DbStop(w http.ResponseWriter, r *http.Request) {
	if dborm.DbClient.XEngine == nil {
		services.ResponseErrorWithJson(w, 400, "无连接")
	}

	// json 請求參數獲取
	var bodyArgs struct {
		ID string `json:"ID"  validate:"required"`
	}
	err := ctx.ShouldBindJSON(r, &bodyArgs)
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseErrorWithJson(w, 400, err.Error())
		return
	}

	// 关闭
	rse, err := dborm.DbClient.XEngine.Exec("KILL ?;", bodyArgs.ID)
	if err != nil {
		services.ResponseErrorWithJson(w, 500, err.Error())
		return
	}
	services.ResponseWithJson(w, 200, rse)
}

// xorm Get data from database
func TaskDatabaseGetData(w http.ResponseWriter, r *http.Request) {
	log.Debug("DatabaseGetData processing... ")

	var sql []string
	var err error

	vars := mux.Vars(r)
	tblName := vars["objectTypeValue"]
	sql = GetUriSQLArray(r)
	// select as must, todo ...

	if sql == nil {
		wc := services.GetUriWhereString(r)
		if wc == "" {
			sql = append(sql, fmt.Sprintf("select * from %s", tblName))
		} else {
			sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc))
		}
	}

	ls := services.GetUriPageLimitString(r)

	//	data := make([]map[string]interface{}, 0)
	//	xormResponse := make([]map[string]interface{}, len(sql))
	var xormResponse XormResponse
	data := make([]map[string]interface{}, 0)
	for i, s := range sql {
		log.Tracef("SQL[%d]: %s", i, sql[i])

		rows := make([]map[string]interface{}, 0)
		mapRows := make(map[string]interface{})

		if s != "" {
			//			err = XEngine.SQL(s).Find(&rows)
			if IsQuerySQL(s) == false {
				services.ResponseNotAcceptable406QuerySQLError(w)
				return
			}

			querySQL := s
			if i == (len(sql) - 1) {
				querySQL = querySQL + " " + ls
			}
			log.Debug("querySQL:", querySQL)
			rows, err = DbClient.XEngine.QueryInterface(querySQL)
			if err != nil {
				log.Error("SQL failed:", err)
				services.ResponseInternalServerError500DatabaseOperationFailed(w)
				return
			}
			tableName := GetTableName(s)
			log.Debugf("s:%s tableName:%s", s, tableName)
			mapRows[tableName] = rows
			data = append(data, mapRows)
			log.Trace("data:", data)
		}
		i++
	}
	xormResponse.Data = data

	services.ResponseWithJson(w, http.StatusOK, xormResponse)
}

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

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
	if err != nil {
		log.Error("io.ReadAll failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	vars := mux.Vars(r)
	tableName := vars["objectTypeValue"]
	log.Debug("Request body:", string(body), "tableName:", tableName)
	insertData := make(map[string]interface{})
	_ = json.Unmarshal(body, &insertData)

	tn, sql := dborm.ConstructInsertSQL(tableName, insertData)
	log.Tracef("tn: %s sql :%s", tn, sql)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	var affected int64
	for _, s := range sql {
		res, err := xSession.Exec(s)
		if err != nil {
			log.Error("Insert failed:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
		n, _ := res.RowsAffected()
		affected = affected + n
	}
	xSession.Commit()
	//	affected, err := InsertDataWithJson(insertData)
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tn] = row
	//	xormResponse.Data = mapRow
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

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

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	vars := mux.Vars(r)
	tblName := vars["objectTypeValue"]
	wc := services.GetUriWhereString(r)

	log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc)
	updateData := make(map[string]interface{})
	_ = json.Unmarshal(body, &updateData)

	tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc)
	log.Tracef("tn: %s sql :%s", tn, sql)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	var affected int64
	for _, s := range sql {
		res, err := xSession.Exec(s)
		if err != nil {
			log.Error("Update failed:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
		n, _ := res.RowsAffected()
		affected = affected + n
	}
	xSession.Commit()
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tn] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}

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

	vars := mux.Vars(r)
	tblName := vars["objectTypeValue"]
	wc := services.GetUriWhereString(r)

	log.Debug("Table name:", tblName, "wc:", wc)

	sql := dborm.ConstructDeleteSQL(tblName, wc)
	xSession := DbClient.XEngine.NewSession()
	defer xSession.Close()
	res, err := xSession.Exec(sql)
	if err != nil {
		log.Error("Update failed, err:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}
	affected, _ := res.RowsAffected()
	xSession.Commit()
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow["data"] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}
