package monitor

import (
	"net/http"
	"sort"
	"strings"
	"time"

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

// 点击【主机 - 监控】菜单，进入监控报表，直观的了解服务器的运行状态，包含【平均负载】、【CPU性能监控】、【内存使用监控】、【磁盘IO监控】、【网络IO监控】

// 可以查看昨天，今天，最近7天，最近30天，自定义时间的监控指标情况。
// 默认监控是开启的，可以在【面板设置 - 监控】页面中根据需求对监控进行开启和关闭。
// 监控数据默认保存30天，可以自行修改，也可手动清理该日志。

var (
	// IP地址
	UriIPAddr = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/ipaddr"
	// 可选网络
	UriNetOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/netoptions"
	// 可选磁盘
	UriIoOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/iooptions"
	// 加载
	UriLoad = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/load"

	// IP地址
	UriIPAddrOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/ipaddr"
	// 可选网络
	UriNetOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/netoptions"
	// 可选磁盘
	UriIoOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/iooptions"
	// 加载
	UriLoadOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/load"
)

// IPAddr IP地址
func IPAddr(w http.ResponseWriter, r *http.Request) {
	ipAddrs := []map[string]string{}
	interfaces, err := net.Interfaces()
	if err == nil {
		for _, iface := range interfaces {
			addrs := map[string]string{}
			for _, v := range iface.Addrs {
				prefix := strings.Split(v.Addr, "/")[0]
				if strings.Contains(prefix, "::") {
					addrs["IPv6"] = prefix
				}
				if strings.Contains(prefix, ".") {
					addrs["IPv4"] = prefix
				}
			}
			ipAddrs = append(ipAddrs, addrs)
		}
	}
	services.ResponseWithJson(w, 200, ipAddrs)
}

// Netoptions 可选网络
func Netoptions(w http.ResponseWriter, r *http.Request) {
	netStat, _ := net.IOCounters(true)
	var options []string
	options = append(options, "all")
	for _, net := range netStat {
		options = append(options, net.Name)
	}
	sort.Strings(options)
	services.ResponseWithJson(w, 200, options)
}

// Iooptions 可选磁盘
func Iooptions(w http.ResponseWriter, r *http.Request) {
	diskStat, _ := disk.IOCounters()
	var options []string
	options = append(options, "all")
	for _, net := range diskStat {
		options = append(options, net.Name)
	}
	sort.Strings(options)
	services.ResponseWithJson(w, 200, options)
}

// LoadMonitor 载入监控
func LoadMonitor(w http.ResponseWriter, r *http.Request) {
	// json 請求參數獲取
	var bodyArgs MonitorSearch
	err := ctx.ShouldBindJSON(r, &bodyArgs)
	if err != nil || dborm.DbClient.XEngine == nil {
		services.ResponseErrorWithJson(w, 400, err.Error())
		return
	}

	loc := time.Now().Location()
	bodyArgs.StartTime = bodyArgs.StartTime.In(loc)
	bodyArgs.EndTime = bodyArgs.EndTime.In(loc)

	var backdatas []MonitorData
	if bodyArgs.Param == "all" || bodyArgs.Param == "cpu" || bodyArgs.Param == "memory" || bodyArgs.Param == "load" {
		var bases []MonitorBase
		err := dborm.DbClient.XEngine.Table("monitor_base").
			Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime).
			Desc("created_at").
			Find(&bases)
		if err != nil {
			services.ResponseErrorWithJson(w, 400, err.Error())
			return
		}

		var itemData MonitorData
		itemData.Param = "base"
		for _, base := range bases {
			itemData.Date = append(itemData.Date, base.CreatedAt)
			itemData.Value = append(itemData.Value, base)
		}
		backdatas = append(backdatas, itemData)
	}
	if bodyArgs.Param == "all" || bodyArgs.Param == "io" {
		var bases []MonitorIO
		err := dborm.DbClient.XEngine.Table("monitor_io").
			Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime).
			Desc("created_at").
			Find(&bases)
		if err != nil {
			services.ResponseErrorWithJson(w, 400, err.Error())
			return
		}

		var itemData MonitorData
		itemData.Param = "io"
		for _, base := range bases {
			itemData.Date = append(itemData.Date, base.CreatedAt)
			itemData.Value = append(itemData.Value, base)
		}
		backdatas = append(backdatas, itemData)
	}
	if bodyArgs.Param == "all" || bodyArgs.Param == "network" {
		var bases []MonitorNetwork
		err := dborm.DbClient.XEngine.Table("monitor_network").
			Where("name = ? AND created_at > ? AND created_at < ?", bodyArgs.Info, bodyArgs.StartTime, bodyArgs.EndTime).
			Desc("created_at").
			Find(&bases)
		if err != nil {
			services.ResponseErrorWithJson(w, 400, err.Error())
			return
		}

		var itemData MonitorData
		itemData.Param = "network"
		for _, base := range bases {
			itemData.Date = append(itemData.Date, base.CreatedAt)
			itemData.Value = append(itemData.Value, base)
		}
		backdatas = append(backdatas, itemData)
	}
	services.ResponseWithJson(w, 200, backdatas)
}
