package service

import (
	"encoding/json"
	"fmt"
	"git.quantgroup.cn/DevOps/enoch/service/data"
	"git.quantgroup.cn/DevOps/enoch/service/file_cache"
	"git.quantgroup.cn/DevOps/enoch/service/log"
	"github.com/gomodule/redigo/redis"
	"github.com/influxdata/influxdb/client/v2"
	"log"
	"time"
)

type BraveMessageHandler struct {
}

var httpMethod = map[string]string{
	"get": "", "GET": "", "post": "", "options": "", "put": "", "delete": "", "head": "",
}

func (BraveMessageHandler) MsgProcess(msg string) {

	traceMsg := make([]TraceMsg, 3) //[]TraceMsg{}
	err := json.Unmarshal([]byte(msg), &traceMsg)
	if err != nil {
		fmt.Println(err)
	}

	//msgRedisProcess(traceMsg)
	msgInfluxProcess(traceMsg)
}

var batchSize = 5000
var pointSlice = make([]*client.Point, 0, batchSize)

func msgInfluxProcess(traceMsgs []TraceMsg) {

	for _, traceMsg := range traceMsgs {

		if traceMsg.Kind != "SERVER" {
			continue
		}
		path := traceMsg.Name

		if _, ok := httpMethod[path]; ok {
			path = traceMsg.Tags.HttpMethod + " " + traceMsg.Tags.HttpPath
		}

		sysName := traceMsg.LocalEndpoint.ServiceName

		fields := make(map[string]interface{})
		fields["duration"] = traceMsg.Duration / 1000
		fields["traceId"] = traceMsg.TraceId
		bytes, err := json.Marshal(traceMsg)

		msg := string(bytes)

		fields["msg"] = msg

		tags := make(map[string]string)
		tags["sys_name"] = sysName
		tags["path"] = path
		tags["host"] = traceMsg.LocalEndpoint.Ipv4

		if err != nil {
			log.Fatal(err)
		}

		unix := time.Unix(0, traceMsg.Timestamp*1000)
		if len(pointSlice) == batchSize {
			go batchWrite(pointSlice)
			pointSlice = make([]*client.Point, 0, batchSize)
		}

		point, _ := client.NewPoint("trace_info", tags, fields, unix)
		pointSlice = append(pointSlice, point)

		if err != nil {
			log.Fatal(err, msg)
		}
	}

}

func batchWrite(pointArray []*client.Point) {
	if file_cache.Enabled() {
		logger.Info.Println("写入缓存")
		fileWrite(pointArray)
	} else {
		err := httpWrite(pointArray)
		if err != nil {
			file_cache.OpenCache()
			fileWrite(pointArray)
		}
		logger.Info.Println("写入influx", len(pointArray))
	}
}



func httpWrite(pointArray []*client.Point) error {
	c := data.NewClient()
	defer func() { _ = c.Close() }()

	points, err := client.NewBatchPoints(client.BatchPointsConfig{
		Database: "monitor",
		//Precision : "ms",
	})
	if err != nil {
		return err
	}

	points.AddPoints(pointArray)
	err = c.Write(points)
	if err != nil {
		return err
	}
	return nil
}
func ReSubmit(data []string) error {
	pointSlice := make([]*client.Point, 0)
	for _, v := range data {
		cp := file_cache.CreateCachePoint(v)
		point, err := client.NewPoint(cp.Name, cp.Tags, cp.Fields, cp.Time)
		if err != nil {
			logger.Error.Println("构造client.point异常", err)
		}
		pointSlice = append(pointSlice, point)
		if len(pointSlice) > 1000 {
			err := httpWrite(pointSlice)
			if err != nil {
				return  err
			}
			logger.Info.Println("缓存重新提交：1000")
			pointSlice = make([]*client.Point, 0)
		}
	}
	if len(pointSlice) > 0 {
		err := httpWrite(pointSlice)
		if err != nil {
			logger.Info.Println(pointSlice)
			return  err
		}
		logger.Info.Println("缓存重新提交：", len(pointSlice))
	}
	logger.Info.Println("重新提交")
	return nil
}

func fileWrite(pointArray []*client.Point) {
	for _, p := range pointArray {
		if p != nil {
			current := file_cache.NewPoint(p)
			data, err := json.Marshal(current)
			if err != nil {
				fmt.Println(err)
			}
			file_cache.Write(string(data))
		}
	}
}

func Duration(day string, fun func(sysName string, durations map[string]string)) {

	conn := data.Pool.Get()
	defer func() { _ = conn.Close() }()
	matchPattern := "duration*" + day
	reply, err := redis.Values(conn.Do("scan", 0, "match", matchPattern, "count", 10000))
	if err != nil {
		fmt.Print("Scan 扫描key出错", err)
	}

	redisKeys := reply[1].([]interface{})
	for _, redisKey := range redisKeys {

		reply2, err := redis.StringMap(conn.Do("zrevrangebyscore", redisKey, "+inf", 200000, "withscores"))
		if err != nil {
			fmt.Print("获取出错了", err)
		}
		fun(string(redisKey.([]uint8)), reply2)
	}

}

func Counter(day string, fun func(sysName string, durations map[string]string)) {
	conn := data.Pool.Get()
	defer func() { _ = conn.Close() }()
	matchPattern := "counter*" + day
	reply, err := redis.Values(conn.Do("scan", 0, "match", matchPattern, "count", 10000))
	if err != nil {
		fmt.Print("Scan 扫描key出错", err)
	}
	redisKeys := reply[1].([]interface{})
	for _, redisKey := range redisKeys {

		reply2, err := redis.StringMap(conn.Do("zrevrange", redisKey, 0, 300, "withscores"))
		if err != nil {
			fmt.Print("获取出错了", err)
		}
		fun(string(redisKey.([]uint8)), reply2)
	}

}
