package node_check

import (
	"context"
	"git.quantgroup.cn/DevOps/enoch/service/dingding"
	"git.quantgroup.cn/DevOps/enoch/service/log"
	"git.quantgroup.cn/DevOps/enoch/service/registry"
	"net/http"
	"os"
	"sync"
	"time"
)

const (
	Passing  = "passing"
	Critical = "critical"
)

var HandlerMap = new(sync.Map)
var HttpGetRetryCount = 3
var HttpTimeOut = time.Second * 10

func init() {
	HandlerMap.Store("aaaa", "http://www.baidasdfasdfasdfasdfu.com/")
	//	HandlerMap.Store("aaaa", "http://172.20.6.33:8989/service-down")
	//TODO 灵活配置
	HandlerMap.Store("heimdallr", "http://172.20.6.33:8989/service-down")
}

func httpGet(url string, timeout time.Duration) (*http.Response, error) {
	ctx, cancel := context.WithCancel(context.TODO())

	req, e := http.NewRequest("GET", url, nil)
	if e != nil {
		return nil, e
	} else {
		req = req.WithContext(ctx)
	}

	_ = time.AfterFunc(timeout, func() {
		cancel()
	})

	return http.DefaultClient.Do(req)
}

func handler(serviceName string) {
	if url, ok := HandlerMap.Load(serviceName); ok {
		for i := 0; i < HttpGetRetryCount; i++ {
			if resp, e := httpGet(url.(string), HttpTimeOut); e != nil {
				logger.Error.Print(" handler service: ", serviceName, " ", e)
			} else {
				logger.Info.Print(" handler service: ", serviceName, " ", resp.StatusCode)
				break
			}
		}
	} else {
		logger.Info.Print(" handler service: ", serviceName, " ", "not found handler hook api")
	}
}

type watch struct{}

func (w watch) DeleteService(serviceName string) {
	//pass
}

func serviceStatus(service *registry.Service) bool {
	for _, node := range service.NodeMap {
		if node.Status == Passing {
			return true
		}
	}

	return false
}

func serviceStr(service *registry.Service) string {
	rtn := service.Name + " "

	for _, node := range service.NodeMap {
		rtn += node.Id + ":" + node.Status + " "
	}

	return rtn
}

func (w watch) UpdateNodes(service *registry.Service) {
	servicesStatusLock.Lock()
	defer servicesStatusLock.Unlock()

	//单个节点挂了告警
	if oldService, ok := servicesStatus[service.Name]; ok {
		for _, node := range service.NodeMap {
			if oldNode, ok := oldService.NodeMap[node.Id]; ok {
				if oldNode.Status == Passing && node.Status == Critical {
					logger.Warning.Print(service.Name, " ", node.Id, "---!!!node critical!!!---")
					_ = dingding.SenderDingDing(service.Name+" "+node.Id+" "+"---!!!node critical!!!---", dingding.DefaultDingURL)
				}
			}
		}
	}

	//整个服务挂了告警
	//如果 服务存在，并且服务的old状态为passing，并且服务的now状态为critical，则报警，否贼记录服务状态
	serviceString := serviceStr(service)
	if oldService, ok := servicesStatus[service.Name]; ok && serviceStatus(oldService) && !serviceStatus(service) {
		logger.Warning.Print(serviceString, "---!!!service critical!!!---")
		_ = dingding.SenderDingDing(serviceString+"---!!!service critical!!!---", dingding.DefaultDingURL)
		handler(service.Name)
	} else {
		logger.Info.Print(serviceString)
	}

	//更新服务状态
	//深拷贝对象
	newService := registry.NewService(service.Name)
	for kk, vv := range service.NodeMap {
		newNode := registry.Node{
			ServiceName:vv.ServiceName,
			Id:vv.Id,
			Port:vv.Port,
			Address:vv.Address,
			Status:vv.Status,
		}
		for x, y := range vv.Meta {
			newNode.Meta[x] = y
		}
		newService.NodeMap[kk] = &newNode
	}

	servicesStatus[service.Name] = newService
}

func (w watch) AddNode(node *registry.Node) {
	//pass
}

func (w watch) DelNode(node *registry.Node) {
	//pass
}

var (
	servicesStatus = make(map[string]*registry.Service)
	servicesStatusLock = new(sync.Mutex)
)

func InitServiceStatus() {
	servicesStatus = registry.GetServiceMap()
}

func NodeCheck() {
	defer func() {
		if e := recover(); e != nil {
			logger.Info.Print("node check panic: ", e)
			_ = dingding.SenderDingDing("node check panic!", dingding.DefaultDingURL)
			time.Sleep(time.Second * 1)
			NodeCheck()
		}
	}()

	//注册器初始化
	dc := "3c"
	cluster := []string{"172.30.12.2:8500", "172.30.12.3:8500", "172.30.12.4:8500"}
	if e := registry.Init("consul", map[string]interface{}{"dc": dc, "cluster": cluster}); e != nil {
		logger.Info.Print("registry init error:", e)
		os.Exit(-1)
	}
	time.Sleep(time.Second * 1)

	//服务状态初始化
	InitServiceStatus()

	//设置观察者
	if e := registry.SetObserver("watch", &watch{}); e != nil {
		logger.Info.Print("set observer error:", e)
		os.Exit(-1)
	}

	select {}
}
