package alarm

import (
	"git.quantgroup.cn/DevOps/enoch/service/log"
	"github.com/influxdata/influxdb/client/v2"
	"reflect"
	"strings"
)

func BuildSql(strategies []Strategy) string {
	var sqlBuff strings.Builder
	for _, strategy := range strategies {
		sqlBuff.WriteString(strategy.Sql)
	}
	return sqlBuff.String()
}

var operators = reflect.ValueOf(Compare{})

func needIgnore(ignoreTag map[string]bool, tags []string) bool {
	for _, k := range tags {
		if ignoreTag[k] {
			return true
		}
	}
	return false
}

func getAlterValue(personalAlterValue map[string][]string, uniqueTag string, tags []string, alterValue []string) []string {
	value := personalAlterValue[uniqueTag]
	if nil != value {
		return value
	}
	tagLen := len(tags)
	for i := 1; i < tagLen; i++ {
		if nil != personalAlterValue[tags[i]] {
			return personalAlterValue[tags[i]]
		}
	}
	return alterValue
}

func getTagValues(keys []string, tag map[string]string) []string {
	values := make([]string, len(keys))
	for i, k := range keys {
		values[i] = tag[k]
	}
	return values
}

func DealResult(res []client.Result, strategies []Strategy) {
	var resIndex = 0
	for _, strategy := range strategies {
		logger.Info.Println("-------", strategy.Name, resIndex, "---------")
		operator := strategy.Operator
		method := operators.MethodByName(operator)
		alterValue := strategy.AlterValue
		alterValueLen := len(alterValue)
		ignoreTag := strategy.IgnoreTag
		tags := strategy.Tag
		personalAlterValue := strategy.PersonalAlterValue
		if strategy.SqlLen == 1 { //单sql
			result := res[resIndex]
			for _, series := range result.Series {
				uniqueTag := series.Tags[tags[0]]
				tagValues := getTagValues(tags, series.Tags)
				if needIgnore(ignoreTag, tags) {
					continue
				}
				value := series.Values[0][1]
				if nil == value { //todo 空值报警
					logger.Warning.Println(strategy.Name, ":", uniqueTag, ":", "空值")
				}

				currentAlterValue := getAlterValue(personalAlterValue, uniqueTag, tagValues, alterValue)
				params := make([]reflect.Value, alterValueLen+1)
				for j, arg := range currentAlterValue {
					params[j] = reflect.ValueOf(arg)
				}
				params[alterValueLen] = reflect.ValueOf(reflect.ValueOf(value).String())
				logger.Info.Println(uniqueTag, params)
				rs := method.Call(params)
				logger.Info.Println(uniqueTag, ": real:", value, ": check", rs[0])
			}
		} else {
			params := make(map[string][]reflect.Value)
			for i := 0; i < strategy.SqlLen; i++ {
				resIndex += i
				for _, series := range res[resIndex].Series {
					if needIgnore(ignoreTag, tags) {
						continue
					}
					uniqueTag := series.Tags[tags[0]]
					tagValues := getTagValues(tags, series.Tags)
					value := series.Values[0][1]

					if nil == value { //todo 空值报警
						params[uniqueTag] = nil
						logger.Warning.Println(strategy.Name, ":", uniqueTag, ":", "空值")
					}

					if nil == params[uniqueTag] {
						currentParams := make([]reflect.Value, strategy.SqlLen+alterValueLen)

						currentAlterValue := getAlterValue(personalAlterValue, uniqueTag, tagValues, alterValue)
						for k, arg := range currentAlterValue {
							currentParams[k] = reflect.ValueOf(arg)
						}

						params[uniqueTag] = currentParams
					}
					params[uniqueTag][alterValueLen+i] = reflect.ValueOf(reflect.ValueOf(value).String())

				}
			}
			for k, v := range params {
				if nil == v {
					continue
				}
				logger.Info.Println(k, v)
				rs := method.Call(v)
				//todo 结果报警
				logger.Info.Println(k, ": real:", v, ": check", rs[0])
			}
		}
		//循环结果集
		resIndex += 1
	}
	logger.Info.Fatal("结束")
}

func CheckArray(strategies []Strategy) bool {

	for _, strategy := range strategies {
		if !Check(strategy) {
			return false
		}
	}
	return true
}

func Check(strategy Strategy) bool {
	if "" == strategy.Name {
		return false
	}

	if "" == strategy.Name {
		return false
	}

	if strategy.SqlLen != strings.Count(strategy.Sql, ";") {
		return false
	}

	if len(strategy.Tag) < 1 {
		return false
	}
	length := len(strategy.AlterValue)
	for _, v := range strategy.PersonalAlterValue {
		if len(v) != length {
			return false
		}
	}

	return true
}
