package odbcmql

import (
	"fmt"
	"regexp"
	"strings"

	odb "git.wecise.com/wecise/odb-go/odb"
	"gitee.com/wecisecode/util/cast"
)

func MatchValues(rtn *odb.Result, ks []string, ms []any) (x int, matchingvalues [][]any) {
	var matchingvalue any
	for _, dat := range rtn.Data {
		matchingvalues = append(matchingvalues, []any{})
		m := false
		sv := ""
		match := true
		for i, k := range ks {
			matchingvalue = dat[k]
			m, sv = matchvalue(ms[i], matchingvalue)
			if !m {
				ks := strings.Split(k, ".")
				if len(ks) <= 1 {
					match = false
					break
				} else {
					k := ""
					for i := 0; match && i < len(ks); i++ {
						if matchingvalue == nil {
							if k != "" {
								k += "."
							}
							k += ks[i]
							matchingvalue = dat[k]
							if matchingvalue == nil && ks[i] == "len" {
								matchingvalue = 0
							}
						} else {
							switch mv := matchingvalue.(type) {
							case map[string]any:
								matchingvalue = mv[ks[i]]
								if matchingvalue == nil && ks[i] == "len" {
									matchingvalue = len(mv)
								}
							case []any:
								if ks[i] == "len" {
									matchingvalue = len(mv)
								} else {
									n, e := cast.ToIntE(ks[i])
									if e != nil {
										match = false
										break
									}
									if n >= len(mv) {
										match = false
										break
									}
									matchingvalue = mv[n]
								}
							case string:
								if ks[i] == "len" {
									matchingvalue = len(mv)
								} else {
									n, e := cast.ToIntE(ks[i])
									if e != nil {
										match = false
										break
									}
									if n >= len(mv) {
										match = false
										break
									}
									matchingvalue = mv[n]
								}
							default:
								if ks[i] == "len" {
									matchingvalue = 0
								} else {
									matchingvalue = nil
								}
							}
						}
					}
					m, sv = matchvalue(ms[i], matchingvalue)
					if !m {
						match = false
						break
					}
				}
			}
			matchingvalues[len(matchingvalues)-1] = append(matchingvalues[len(matchingvalues)-1], sv)
		}
		if match {
			x++
			matchingvalues = matchingvalues[:len(matchingvalues)-1]
		} else {
			matchingvalues[len(matchingvalues)-1] = append(matchingvalues[len(matchingvalues)-1], sv)
		}
	}
	return
}

func matchvalue(matcher any, matchingvalue any) (bool, string) {
	switch m := matcher.(type) {
	case *regexp.Regexp:
		switch v := matchingvalue.(type) {
		case string:
			return m.MatchString(v), v
		default:
			sv := fmt.Sprintf("%#v", matchingvalue)
			return m.MatchString(sv), sv
		}
	case string:
		sv := ""
		switch matchingvalue.(type) {
		case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, bool:
			sv = fmt.Sprintf("%v", matchingvalue)
		case float32, float64:
			sv = fmt.Sprintf("%v", matchingvalue)
			fvrange := strings.Split(m, "~")
			if len(fvrange) > 1 {
				return sv >= fvrange[0] && sv <= fvrange[len(fvrange)-1], sv
			}
		default:
			sv = fmt.Sprintf("%#v", matchingvalue)
		}
		return sv == m, sv
	case *Action:
		switch m.Name {
		case "<FUZZY>":
			return matchFuzzy(matchingvalue, m.Args)
		}
	}
	panic("未定义的匹配类型")
}

func matchFuzzy(matchingvalue any, mvrange []any) (bool, string) {
	sv := ""
	switch matchingvalue.(type) {
	case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, bool, float32, float64, string:
		sv = fmt.Sprintf("%v", matchingvalue)
	default:
		sv = fmt.Sprintf("%#v", matchingvalue)
	}
	if len(mvrange) == 0 {
		return false, sv
	}
	m1 := fmt.Sprintf("%v", mvrange[0])
	m2 := fmt.Sprintf("%v", mvrange[len(mvrange)-1])
	return sv >= m1 && sv <= m2, sv
}
