package monitorNewMgr

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"goutil/logUtil"
	"goutil/securityUtil"
	"goutil/webUtil"
)

var (
	// 报告监控信息的URL
	remoteURL = "http://monitorservice.7qule.com/monitor"

	//组Id
	groupId string

	//项目Id
	projectId string

	//组密钥
	groupSecret string

	// 服务器IP
	serverIP string

	// 服务器名称
	serverName string

	// 监控时间间隔(单位：秒钟)
	monitorInterval = 10

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

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

	//未设置参数的提醒
	isWarning bool = false
)

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

		for _, item := range monitorFuncList {
			if err := item(); err != nil {
				errContent := fmt.Sprintf("监控方法实际调用错误:%s", err.Error())
				report(-99, errContent)
			} else {
				report(0, "")
			}
		}
	}

	go func() {
		// monitorNewMgr不能引用goroutineMgr，以避免循环引用
		/*
			goroutineName := fmt.Sprintf("%s.check", "monitorNewMgr")
			goroutineMgr.Monitor(goroutineName)
			defer goroutineMgr.ReleaseMonitor(goroutineName)
		*/

		defer func() {
			if r := recover(); r != nil {
				logUtil.LogUnknownError(r)
			}
		}()

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

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

//监控信息提交返回
type ReportResponse struct {
	//响应结果状态
	ResultStatus string

	// 响应结果数据
	Data string
}

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

// SetParam ...设置参数
//_groupId:组Id
//_groupSecret:组密钥
//_projectId:项目Id
// _serverIP:服务器IP
// _serverName:服务器名称
func SetParam(_groupId, _groupSecret, _projectId, _serverIP, _serverName string) {
	groupId = _groupId
	groupSecret = _groupSecret
	projectId = _projectId
	serverIP = _serverIP
	serverName = _serverName
}

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

	monitorFuncList = append(monitorFuncList, f)
}

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

	timestamp := time.Now().Unix()

	// 判断指定时间内是否已经处理过
	valid := checkSimilarity(content, timestamp)
	if !valid {
		return
	}

	//上传错误
	report(-99, content)
}

// Report2 ...报告异常信息
// title:上报的标题
// contentFmt:报告内容
//code :9999为特殊状态，不加入心跳检测
//isCheckSimilarity：是否去重
// args:参数列表
func Report2(title, contentFmt string, code int, isCheckSimilarity bool, args ...interface{}) {
	content := fmt.Sprintf("Title:%s Content:%s", title, contentFmt)
	if len(args) > 0 {
		content = fmt.Sprintf(content, args...)
	}

	if isCheckSimilarity {
		timestamp := time.Now().Unix()

		// 判断指定时间内是否已经处理过
		valid := checkSimilarity(content, timestamp)
		if !valid {
			return
		}
	}

	//上传错误
	report(code, content)
}

//report 统一上传信息
//code 0为心跳，非零为错误信息
//content 上报内容
func report(code int, content string) {
	if groupId == "" || projectId == "" || groupSecret == "" {
		if !isWarning {
			logUtil.WarnLog("monitorNewMgr没有初始化参数,请调用SetParam进行初始化")
			isWarning = true
		}

		return
	}

	timestamp := time.Now().Unix()
	rawString := fmt.Sprintf("Code=%d&GroupId=%s&ProjectId=%s&ServerIP=%s&ServerName=%s&Content=%s&Timestamp=%d&GroupSecret=%s", code, groupId, projectId, serverIP, serverName, content, timestamp, groupSecret)
	sign := securityUtil.Md5String(rawString, true)

	//构造参数对象
	monitorModel := newMonitorModel(code, groupId, projectId, serverIP, serverName, content, timestamp, sign)

	//定义错误信息
	var logMessage string

	//定义参数
	jsonMonitorModel, err := json.Marshal(monitorModel)
	if err != nil {
		logMessage = fmt.Sprintf("json.Marshal(monitorModel),err：%s", err.Error())
		logUtil.ErrorLog(logMessage)
		return
	}

	postDataDict := make(map[string]string)
	postDataDict["MonitorModel"] = string(jsonMonitorModel)

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

	statusCode, result, err := webUtil.PostMapData(remoteURL, postDataDict, header, transport)
	//statusCode, result, err := webUtil.PostMapData(remoteURL, postDataDict, webUtil.ContentType_Form, nil)
	if err != nil {
		logMessage = fmt.Sprintf("MonitorModel:，错误信息为：%s", err.Error())
		logUtil.ErrorLog(logMessage)
		return
	}
	if statusCode != 200 {
		logMessage = fmt.Sprintf("MonitorReport:%d is wrong", statusCode)
		logUtil.ErrorLog(logMessage)
		return
	}

	var reportResponseObj *ReportResponse
	err = json.Unmarshal(result, &reportResponseObj)
	if err != nil {
		logMessage = fmt.Sprintf("json.Unmarshal(reportResponseObj),  result:%s  err：%s", result, err.Error())
		logUtil.ErrorLog(logMessage)
		return
	}

	if reportResponseObj.ResultStatus != "" {
		logMessage = fmt.Sprintf("上传信息返回错误,ResultStatus %s", reportResponseObj.ResultStatus)
		logUtil.ErrorLog(logMessage)
		return
	}
}

//上报数据
func ReportServiceStatus(data interface{}) {
	var commInfo CommInfoModel
	var isServerMsg bool
	var isCenterMsg bool
	//定义错误信息
	var logMessage string

	message, ok := (data).(ServerNodeMessage)
	if ok {
		isServerMsg = true
		commInfo = message.CommInfo
		//处理数据
		return
	} else {
		message, ok := (data).(MonitorCenterMessage)
		if ok {
			isCenterMsg = true
			commInfo = message.CommInfo
		}
	}

	//如果类型都不符合，则说明数据格式有问题
	if !isServerMsg && !isCenterMsg {
		logMessage = fmt.Sprintf("上传信息格式错误,ResultStatus %s", data)
		logUtil.ErrorLog(logMessage)
	}

	//构造签名字符串
	rawString := fmt.Sprintf("&GroupId=%s&ProjectId=%s&IP=%s&ServiceName=%s&InstanceId=%s&ClusterId=%s&Timestamp=%d&GroupSecret=%s",
		commInfo.GroupId, commInfo.ProjectId, commInfo.IP, commInfo.ServiceName, commInfo.InstanceId, commInfo.ClusterId, commInfo.Tll, groupSecret)
	// 签名赋值
	commInfo.Sign = rawString

	//定义参数
	jsonMonitorModel, err := json.Marshal(data)
	if err != nil {
		logMessage = fmt.Sprintf("json.Marshal(data),err：%s", err.Error())
		logUtil.ErrorLog(logMessage)
		return
	}
	postDataDict := make(map[string]string)
	postDataDict["MonitorModel"] = string(jsonMonitorModel)

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

	statusCode, result, err := webUtil.PostMapData("http://monitorservice.7qule.com/serviceMonitor", postDataDict, header, transport)
	//statusCode, result, err := webUtil.PostMapData(remoteURL, postDataDict, webUtil.ContentType_Form, nil)
	if err != nil {
		logMessage = fmt.Sprintf("ReportServiceStatus上报数据错误:，错误信息为：%s", err.Error())
		logUtil.ErrorLog(logMessage)
		return
	}
	if statusCode != 200 {
		logMessage = fmt.Sprintf("ReportServiceStatus上报数据错误:%d is wrong", statusCode)
		logUtil.ErrorLog(logMessage)
		return
	}

	var reportResponseObj *ReportResponse
	err = json.Unmarshal(result, &reportResponseObj)
	if err != nil {
		logMessage = fmt.Sprintf("ReportServiceStatus.json.Unmarshal(reportResponseObj),  result:%s  err：%s", result, err.Error())
		logUtil.ErrorLog(logMessage)
		return
	}

	if reportResponseObj.ResultStatus != "" {
		logMessage = fmt.Sprintf("ReportServiceStatus上传信息返回错误,ResultStatus %s", reportResponseObj.ResultStatus)
		logUtil.ErrorLog(logMessage)
		return
	}
}
