package monitorMgr

import (
	"fmt"
	"sync"
	"time"

	"goutil/debugUtil"
	"goutil/logUtil"
	"goutil/webUtil"
)

var (
	// 报告监控信息的URL
	remoteURL = "http://maintenance.7qule.com/Manage/Monitor.ashx"

	// 服务器IP
	serverIP string

	// 服务器名称
	serverName string

	// 监控时间间隔(单位：分钟)
	monitorInterval = 5

	// 重复消息发送的时间间隔（单位：分钟）
	duplicateInterval = 5

	// 已经发送的消息
	sentMessageMap = make(map[string]int64)

	// 已经发送消息的锁对象
	sentMessageMutex sync.Mutex

	// 监控方法列表
	monitorFuncList = make([]func() error, 0, 4)

	// 监控方法锁对象
	monitorFuncMutex sync.Mutex
)

// SetURL ...设置监控信息发送的URL
// url:监控信息发送的URL
func SetURL(url string) {
	remoteURL = url
}

// SetDuplicateInterval ...设置重复消息发送的时间间隔（单位：分钟）
// _duplicateInterval:重复消息发送的时间间隔（单位：分钟）
func SetDuplicateInterval(_duplicateInterval int) {
	duplicateInterval = _duplicateInterval
}

// SetParam ...设置参数
// _serverIP:服务器IP
// _serverName:服务器名称
// _monitorInterval:监控时间间隔(单位：分钟)
func SetParam(_serverIP, _serverName string, _monitorInterval int) {
	serverIP = _serverIP
	serverName = _serverName
	monitorInterval = _monitorInterval
}

// RegisterMonitorFunc ...注册监控方法
// f:监控方法
func RegisterMonitorFunc(f func() error) {
	monitorFuncMutex.Lock()
	defer monitorFuncMutex.Unlock()

	monitorFuncList = append(monitorFuncList, f)
}

// Start ...启动监控服务(obsolete，建议使用Start2)
// serverIp:服务器IP
// serverName:服务器名称
// monitorInterval:监控时间间隔(单位：分钟)
func Start(serverIp, serverName string, monitorInterval int) {
	monitorConfig := NewMonitorConfig(serverIp, serverName, monitorInterval)
	Start2(monitorConfig)
}

// Start ...启动监控服务2
// monitorConfig:监控配置对象
func Start2(monitorConfig *MonitorConfig) {
	// 设置参数
	SetParam(monitorConfig.ServerIp, monitorConfig.ServerName, monitorConfig.Interval)

	// 实际的监控方法调用
	monitorFunc := func() {
		monitorFuncMutex.Lock()
		defer monitorFuncMutex.Unlock()

		for _, item := range monitorFuncList {
			if err := item(); err != nil {
				Report(err.Error())
			}
		}
	}

	go func() {
		// 处理内部未处理的异常，以免导致主线程退出，从而导致系统崩溃
		defer func() {
			if r := recover(); r != nil {
				logUtil.LogUnknownError(r)
			}
		}()

		for {
			// 先休眠，避免系统启动时就进行报警
			time.Sleep(time.Minute * time.Duration(monitorInterval))

			// 实际的监控方法调用
			monitorFunc()
		}
	}()
}

// 判断指定时间内是否已经处理过
// conent:报告内容
func isDuplicate(content string) bool {
	if ts, exists := sentMessageMap[content]; exists && time.Now().Unix()-ts < int64(60*duplicateInterval) {
		return true
	}

	return false
}

// 添加到已发送集合中
// conent:报告内容
func addToMap(content string) {
	sentMessageMap[content] = time.Now().Unix()
}

// Report ...报告异常信息
// format:报告内容格式
// args:具体参数
func Report(format string, args ...interface{}) {
	if len(args) <= 0 {
		Report2(format, "")
	} else {
		Report2(fmt.Sprintf(format, args...), "")
	}
}

// Report ...报告异常信息
// title:上报的标题
// contentFmt:报告内容
// args:参数列表
func Report2(title, contentFmt string, args ...interface{}) {
	content := contentFmt
	if len(args) > 0 {
		content = fmt.Sprintf(contentFmt, args...)
	}

	sentMessageMutex.Lock()
	defer sentMessageMutex.Unlock()

	// 判断指定时间内是否已经处理过
	if isDuplicate(title) {
		return
	}

	logUtil.WarnLog(fmt.Sprintf("MonitorReport:ServerIP:%s,ServerName:%s,Title:%s Content:%s", serverIP, serverName, title, content))

	// 判断是否是DEBUG模式
	if debugUtil.IsDebug() {
		return
	}

	detailMsg := title
	if len(content) > 0 {
		detailMsg = fmt.Sprintf("Title:%s Content:%s", title, content)
	}

	// 定义请求参数
	postDict := make(map[string]string)
	postDict["ServerIp"] = serverIP
	postDict["ServerName"] = serverName
	postDict["Content"] = detailMsg

	//请求url,请求头
	header := webUtil.GetFormHeader()
	transport := webUtil.NewTransport()
	transport.DisableKeepAlives = true
	transport = webUtil.GetTimeoutTransport(transport, 30)

	statusCode, returnBytes, err := webUtil.PostMapData(remoteURL, postDict, header, transport)
	// 连接服务器，以获取数据
	//returnBytes, err := webUtil.PostWebData(remoteURL, postDict, nil)
	if err != nil {
		logUtil.ErrorLog(fmt.Sprintf("MonitorReport:，错误信息为：%s", err))
		return
	}
	if statusCode != 200 {
		logUtil.ErrorLog(fmt.Sprintf("MonitorReport:，状态吗为：%d", statusCode))
		return
	}

	result := string(returnBytes)
	logUtil.WarnLog(fmt.Sprintf("MonitorReport:Result:%s", result))

	if result != "200" {
		logUtil.ErrorLog(fmt.Sprintf("返回值不正确，当前返回值为：%s", result))
	}

	// 添加到已发送集合中
	addToMap(title)
}
