package lm

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

	"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 (
	ExtBackupDataUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}/backup" // for external

	CustomExtBackupDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}/backup" // 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 init() {
// 	conf := config.GetYamlConfig()
// 	InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
// 		conf.Database.Host, conf.Database.Port, conf.Database.Name)
// }

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

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

	vars := mux.Vars(r)
	module := vars["managementModule"]
	dbname := vars["dataStorage"]
	tbname := vars["dataObject"]
	pack := "lm"
	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
	// }

	var sql string
	var filePath string
	switch tbname {
	case "operation_log":
		filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData))
		sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'op_id','account_name','op_ip','subsys_tag','op_type','op_content','op_result','begin_time','end_time','vnf_flag','log_time' union select op_id,account_name,op_ip,subsys_tag,op_type,op_content,op_result,begin_time,end_time,vnf_flag,log_time from operation_log) b", filePath)
	case "security_log":
		filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData))
		sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'id','account_name','account_type','op_ip','op_type','op_content','op_result','op_time' union select id,account_name,account_type,op_ip,op_type,op_content,op_result,op_time from security_log) b", filePath)
	case "alarm_log":
		filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData))
		sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'id','ne_type','ne_id','alarm_seq','alarm_id','alarm_code','alarm_status','event_time','log_time' union select id,ne_type,ne_id,alarm_seq,alarm_id,alarm_code,alarm_status,event_time,log_time from alarm_log) b", filePath)
	default:
		log.Error("error target table")
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}

	res, err := DbClient.XEngine.Exec(sql)
	if err != nil {
		log.Error("Failed to exec SQL:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}
	affected, _ := res.RowsAffected()

	log.Debugf("filePath:%s backup dir:%s", filePath, config.GetYamlConfig().Database.Backup)
	cmd := exec.Command("cp", "-rf", filePath, config.GetYamlConfig().Database.Backup)
	out, err := cmd.CombinedOutput()
	log.Debugf("Exec output: %v", string(out))
	if err != nil {
		log.Error("Faile to exec:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	mapRow := make(map[string]interface{})
	row := map[string]interface{}{"affectedRows": affected}
	mapRow[tbname] = row
	services.ResponseWithJson(w, http.StatusOK, mapRow)
}
