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 (w watch) UpdateNodes(service *registry.Service) {
	//获取服务状态
	serviceOK := false
	nodeStr := ""
	for _, node := range service.NodeMap {
		nodeStr += node.Id + ":" + node.Status + " "
		if node.Status == "passing" {
			serviceOK = true
		}
	}

	//判断是否告警
	if v, ok := servicesStatus.Load(service.Name); ok && v.(string) == Passing && !serviceOK {
		logger.Warning.Print(service.Name, " ", nodeStr, "---!!!service critical!!!---")
		_ = dingding.SenderDingDing(service.Name+" "+nodeStr+" "+"---!!!service critical!!!---", dingding.DefaultDingURL)
		handler(service.Name)
	} else {
		logger.Info.Print(service.Name, " ", nodeStr)
	}

	//更新服务状态
	if serviceOK {
		servicesStatus.Store(service.Name, Passing)
	} else {
		servicesStatus.Store(service.Name, Critical)
	}
}

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

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

var (
	servicesStatus = new(sync.Map)
)

func InitServiceStatus() {
	services := registry.GetServiceMap()
	for _, service := range services {
		serviceOK := false
		for _, node := range service.NodeMap {
			if node.Status == Passing {
				serviceOK = true
				break
			}
		}

		if serviceOK {
			servicesStatus.Store(service.Name, Passing)
		} else {
			servicesStatus.Store(service.Name, Critical)
		}
	}
}

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 {}
}
