package alarm

import (
	"fmt"
	"github.com/influxdata/influxdb/client/v2"
	"github.com/vrg0/go-common/logger"
	"reflect"
	"strings"
)

var operators = reflect.ValueOf(Compare{})
var msgBuilder = reflect.ValueOf(MsgBuilder{})

func DealResult(res []client.Result, strategies []Strategy) {
	var resIndex = 0
	for _, strategy := range strategies {
		logger.Info("-------", strategy.Name, resIndex, "---------")
		operator := strategy.Operator
		operatorMethod := operators.MethodByName(operator)
		buildMsgMethod := msgBuilder.MethodByName(operator)
		alterValue := strategy.AlterValue
		alterValueLen := len(alterValue)
		ignoreTag := strategy.IgnoreTag
		tags := strategy.Tag
		notice := strategy.Notice
		noDataAlter := strategy.NoDataAlter
		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, tagValues) {
					continue
				}
				value := make([]string,0)
				for _, v := range series.Values {
					value = append(value, fmt.Sprint(v[1]))
				}

				//value := series.Values[0][1]
				if nil == value && noDataAlter { //空值报警

					Sender(tagValues, strategy.Name, "no data", notice)
				}

				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(value)
				logger.Info(uniqueTag, ":alter", params[:1], "-", strings.Join(value, ","))
				rs := operatorMethod.Call(params)
				if rs[0].Bool() { //触发报警策略
					//Sender(tagValues, strategy.Name, s, notice) // 报警
					Sender(tagValues, strategy.Name, buildMsgMethod.Call(params[:1])[0].String(), notice) // 报警
				}

			}
		} else {
			params := make(map[string][]reflect.Value)
			tagValueMap := make(map[string][]string)
			for i := 0; i < strategy.SqlLen; i++ {
				resIndex += i
				for _, series := range res[resIndex].Series {
					uniqueTag := series.Tags[tags[0]]
					tagValues := getTagValues(tags, series.Tags)
					if needIgnore(ignoreTag, tagValues) {
						continue
					}
					tagValueMap[uniqueTag] = tagValues
					value := make([]string,0)
					for _, v := range series.Values {
						value = append(value, fmt.Sprint(v[1]))
					}

					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(value)

				}
			}

			for k, v := range params {
				if nil == v || hasNilValue(v) {
					continue
				}

				logger.Info(k, ":", v)
				rs := operatorMethod.Call(v)
				//结果报警
				if rs[0].Bool() { //触发报警策略
					Sender(tagValueMap[k], strategy.Name, buildMsgMethod.Call(v[:1])[0].String(), notice) // 报警
				}
			}
		}
		//循环结果集
		resIndex += 1
	}
}

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
}

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

func hasNilValue(params []reflect.Value) bool {
	for _, c := range params {
		return !c.IsValid()
	}
	return false

}

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
}
