package maintenance

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path"
	"runtime"
	"time"

	"be.ems/lib/core/utils/ctx"
	"be.ems/lib/dborm"
	"be.ems/lib/log"
	"be.ems/lib/services"
	"be.ems/restagent/config"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/mem"
)

// (1)	OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理；
// 对于虚拟化部署OMC系统，能够对虚机内存、虚机CPU、虚拟存储空间、文件系统资源、数据库空间等指标进行监控，提供界面截图       ；

// (2)	系统监控指标的采样时间和阈值可由用户设定，超过阈值将产生不同级别的告警，提供界面截图        ；

// (3)	OMC能够方便的查询数据库连接情况；并可手工干预数据库的连接，能方便的终结非法的数据库连接       ；

// (4)	用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息，提供界面截图
// (5)	用户能方便的对系统进程、应用进程等做中断或者启动操作，提供界面截图

// (6)	对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据，要求OMC能够保存至少3个月，提供界面截图     ；
// (7)	用户可以按照需求自定义报表模板并生成OMC系统维护数据报表，提供界面截图     ；

// (8)	OMC具备自身告警管理功能，对于传统OMC系统，如：服务器单电源告警，存储硬盘告警、OMC系统软件故障等；
// 对于虚拟化OMC系统，如虚机告警、虚拟硬盘告警等，提供界面截图     。

var (
	// parameter config management
	Uri = config.UriPrefix + "/maintenance/{apiVersion}/zz"

	// (1)	OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理；
	UriPref = config.UriPrefix + "/maintenance/{apiVersion}/pref"

	// (6)	对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据，要求OMC能够保存至少3个月，提供界面截图     ；
	UriPrefLog = config.UriPrefix + "/maintenance/{apiVersion}/prefLog"

	// (2)	系统监控指标的采样时间和阈值可由用户设定，超过阈值将产生不同级别的告警，提供界面截图        ；
	UriConfig = config.UriPrefix + "/maintenance/{apiVersion}/config"

	// (3)	OMC能够方便的查询数据库连接情况；并可手工干预数据库的连接，能方便的终结非法的数据库连接
	UriSqlClient = config.UriPrefix + "/maintenance/{apiVersion}/sqlClient"

	// (4)	用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息，提供界面截图
	// (5)	用户能方便的对系统进程、应用进程等做中断或者启动操作，提供界面截图
	UriTop = config.UriPrefix + "/maintenance/{apiVersion}/top"
)

func init() {
	// 定時收集 TODO
	prefLogSave("")
}

func List(w http.ResponseWriter, r *http.Request) {
	fmt.Println("zz List")
	services.ResponseStatusOK200Null(w)
}

// 性能指標
func prefInfo(dirName string) map[string]any {
	data := make(map[string]any)

	// 显示文件資源目录
	dirPath := "D://"
	if runtime.GOOS == "linux" {
		dirPath = "/home"
	}
	// 訪問下級
	if dirName != "" {
		dirPath = path.Join(dirPath, dirName)
	}
	dir_list, e := os.ReadDir(dirPath)
	if e != nil {
		log.Error(e)
	}
	list := make([]map[string]any, 0)
	for _, v := range dir_list {
		o, err := v.Info()
		if err != nil {
			continue
		}
		list = append(list, map[string]any{
			"name":    o.Name(),
			"size":    o.Size(),
			"mode":    o.Mode().String(),
			"modTime": o.ModTime().Format("2006-01-02 15:04:05"),
			"isDir":   o.IsDir(),
		})
	}
	data["dirList"] = list

	// 文件資源使用率
	u, _ := disk.Usage(dirPath)
	usedGB := int(u.Used) / (1024 * 1024 * 1024 * 1)
	data["dirUse"] = fmt.Sprintf("%d", usedGB)

	// CPU使用率
	percent, err := cpu.Percent(time.Second, false)
	if err != nil {
		log.Error(err)
	}
	data["cpuUse"] = fmt.Sprintf("%.2f", percent[0])

	// 内存使用率
	memInfo, err := mem.VirtualMemory()
	if err != nil {
		log.Error(err)
	}
	data["memUse"] = memInfo.UsedPercent

	// 獲取數據庫占用空間
	if dborm.DbClient.XEngine != nil {
		conf := config.GetYamlConfig()
		result, err := dborm.DbClient.XEngine.QueryString(`SELECT 
		CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size,
		CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size,
		CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free,
		CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size 
		FROM information_schema.tables WHERE TABLE_SCHEMA = ?;
		`, conf.Database.Name)
		if err == nil {
			data["dbInfo"] = result[0]
		} else {
			data["dbInfo"] = map[string]string{}
		}
	}
	return data
}

// 性能指標存入數據庫
func prefLogSave(dirName string) {
	if dborm.DbClient.XEngine != nil {
		data := prefInfo(dirName)

		dirListByte, err := json.Marshal(data["dirList"])
		if err != nil {
			log.Error(err)
		}
		dbInfoByte, err := json.Marshal(data["dbInfo"])
		if err != nil {
			log.Error(err)
		}
		rse, err := dborm.DbClient.XEngine.Exec(`INSERT INTO sys_perf_data
		(id, create_time, dir_used, dir_list, db_info, mem_used, cpu_used)
		VALUES(NULL, NOW(), ?, ?, ?, ?, ?);
		`, data["dirUse"], string(dirListByte), string(dbInfoByte), data["memUse"], data["cpuUse"])
		if err != nil {
			log.Error(err)
		}
		fmt.Println(rse.LastInsertId())
	}
}

// GET http://192.168.21.183:3040/api/rest/maintenance/v1/pref?dir=true
func Pref(w http.ResponseWriter, r *http.Request) {
	// 知道下級文件資源目录
	dirName := r.URL.Query().Get("dirName")
	data := prefInfo(dirName)
	services.ResponseWithJson(w, http.StatusOK, data)
}

// POST http://192.168.21.183:3040/api/rest/maintenance/v1/config
func Config(w http.ResponseWriter, r *http.Request) {
	// json 請求參數獲取
	var bodyArgs struct {
		Key   string `json:"key"`
		Value string `json:"value"`
	}
	err := ctx.ShouldBindJSON(r, &bodyArgs)
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	// 進行值更新
	if dborm.DbClient.XEngine != nil {
		result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(result)
		rse, err := dborm.DbClient.XEngine.Exec("UPDATE sys_config SET value = ? where id = ?", "true", 100)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(rse)
	}

	services.ResponseStatusOK200Null(w)
}

// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=close
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=connet
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=user
func SqlClient(w http.ResponseWriter, r *http.Request) {
	// 关闭
	isClose := r.URL.Query().Get("type")
	if isClose == "close" && dborm.DbClient.XEngine != nil {
		dborm.DbClient.XEngine.Close()
	}

	// 重连
	isConnet := r.URL.Query().Get("type")
	if isConnet == "connet" && dborm.DbClient.XEngine == nil {
		conf := config.GetYamlConfig()
		err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
			conf.Database.Host, conf.Database.Port, conf.Database.Name)
		if err != nil {
			fmt.Println("dborm.initDbClient err:", err)
			services.ResponseInternalServerError500DatabaseOperationFailed(w)
			return
		}
	}

	// 查询实例
	isUser := r.URL.Query().Get("type")
	if isUser == "user" && dborm.DbClient.XEngine != nil {
		result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(result)
		rse, err := dborm.DbClient.XEngine.Exec("KILL CONNECTION CONNECTION_ID()")
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(rse)
	}

	// 进行连接测试
	err := dborm.DbClient.XEngine.Ping()
	if err != nil {
		fmt.Println(err)
	}
	services.ResponseStatusOK200Null(w)
}

// GET http://192.168.21.183:3040/api/rest/maintenance/v1/top?grep=
func Top(w http.ResponseWriter, r *http.Request) {
	// 過濾命令
	grep := r.URL.Query().Get("grep")
	// 命令拼接
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "linux":
		command := "ps -ef "
		if grep != "" {
			command += grep
		}
		cmd = exec.Command(command)
	case "windows":
		command := "wmic process list brief "
		if grep != "" {
			command += grep
		}
		cmd = exec.Command("cmd", "/C", command)
	}

	out, err := cmd.CombinedOutput()
	fmt.Println(string(out))
	if err != nil {
		fmt.Println(err)
	}
	services.ResponseWithJson(w, http.StatusOK, string(out))
}

// PATCH http://192.168.21.183:3040/api/rest/maintenance/v1/top?ops=&name=
func TopOps(w http.ResponseWriter, r *http.Request) {
	// json 請求參數獲取
	var bodyArgs struct {
		Ops string `json:"ops"`
		Pid string `json:"pid"`
	}
	err := ctx.ShouldBindJSON(r, &bodyArgs)
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	// 命令拼接
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "linux":
		switch bodyArgs.Ops {
		case "kill":
			cmd = exec.Command("kill", "-9", bodyArgs.Pid)
		}
	case "windows":
		switch bodyArgs.Ops {
		case "kill":
			cmd = exec.Command("cmd", "/C", "taskkill", "-PID", bodyArgs.Pid, "-F")
		}
	}

	out, err := cmd.CombinedOutput()
	fmt.Println(string(out))
	if err != nil {
		fmt.Println(err)
	}
	services.ResponseWithJson(w, http.StatusOK, string(out))
}
