package utils

import (
	"errors"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// Rules 验证规则类型
type Rules map[string][]string

// RulesMap 规则映射类型
type RulesMap map[string]Rules

// CustomizeMap 自定义规则映射
var CustomizeMap = make(map[string]Rules)

// 预定义验证规则
var (
	IdVerify               = Rules{"ID": []string{NotEmpty()}}
	ApiVerify              = Rules{"Path": {NotEmpty()}, "Description": {NotEmpty()}, "ApiGroup": {NotEmpty()}, "Method": {NotEmpty()}}
	MenuVerify             = Rules{"Path": {NotEmpty()}, "Name": {NotEmpty()}, "Component": {NotEmpty()}, "Sort": {Ge("0")}}
	MenuMetaVerify         = Rules{"Title": {NotEmpty()}}
	LoginVerify            = Rules{"Username": {NotEmpty()}, "Password": {NotEmpty()}}
	RegisterVerify         = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
	PageInfoVerify         = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
	CustomerVerify         = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
	AutoCodeVerify         = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}}
	AutoPackageVerify      = Rules{"PackageName": {NotEmpty()}}
	AuthorityVerify        = Rules{"AuthorityId": {NotEmpty()}, "AuthorityName": {NotEmpty()}}
	AuthorityIdVerify      = Rules{"AuthorityId": {NotEmpty()}}
	OldAuthorityVerify     = Rules{"OldAuthorityId": {NotEmpty()}}
	ChangePasswordVerify   = Rules{"Password": {NotEmpty()}, "NewPassword": {NotEmpty()}}
	SetUserAuthorityVerify = Rules{"AuthorityId": {NotEmpty()}}
)

// RegisterRule 注册自定义规则方案建议在路由初始化层即注册
func RegisterRule(key string, rule Rules) (err error) {
	if CustomizeMap[key] != nil {
		return errors.New(key + "已注册,无法重复注册")
	}
	CustomizeMap[key] = rule
	return nil
}

// NotEmpty 非空验证
func NotEmpty() string {
	return "notEmpty"
}

// Ge 大于等于验证
func Ge(value string) string {
	return "ge=" + value
}

// Le 小于等于验证
func Le(value string) string {
	return "le=" + value
}

// Gt 大于验证
func Gt(value string) string {
	return "gt=" + value
}

// Lt 小于验证
func Lt(value string) string {
	return "lt=" + value
}

// Eq 等于验证
func Eq(value string) string {
	return "eq=" + value
}

// Ne 不等于验证
func Ne(value string) string {
	return "ne=" + value
}

// Len 长度验证
func Len(value string) string {
	return "len=" + value
}

// MinLen 最小长度验证
func MinLen(value string) string {
	return "minLen=" + value
}

// MaxLen 最大长度验证
func MaxLen(value string) string {
	return "maxLen=" + value
}

// Regexp 正则验证
func Regexp(value string) string {
	return "regexp=" + value
}

// RegexpMatch 正则校验 校验输入项是否满足正则表达式
func RegexpMatch(rule string) string {
	return "regexp=" + rule
}

// Verify 验证结构体字段
func Verify(st interface{}, rules Rules) error {
	compareMap := map[string]bool{
		"lt": true, "le": true, "eq": true, "ne": true, "ge": true, "gt": true,
	}

	typ := reflect.TypeOf(st)
	val := reflect.ValueOf(st)

	// 处理指针类型
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
		val = val.Elem()
	}

	kd := val.Kind()
	if kd != reflect.Struct {
		return errors.New("expect struct")
	}

	num := val.NumField()
	for i := 0; i < num; i++ {
		tagVal := typ.Field(i)
		fieldVal := val.Field(i)
		fieldName := tagVal.Name

		// 递归处理嵌套结构体
		if tagVal.Type.Kind() == reflect.Struct {
			if err := Verify(fieldVal.Interface(), rules); err != nil {
				return err
			}
		}

		// 检查是否有验证规则
		if ruleList, ok := rules[fieldName]; ok {
			for _, rule := range ruleList {
				switch {
				case rule == "notEmpty":
					if isBlank(fieldVal) {
						return errors.New(fieldName + "值不能为空")
					}
				case strings.HasPrefix(rule, "regexp="):
					if !regexpMatch(strings.Split(rule, "=")[1], fieldVal.String()) {
						return errors.New(fieldName + "格式校验不通过")
					}
				case compareMap[strings.Split(rule, "=")[0]]:
					if !compareVerify(fieldVal, rule) {
						return errors.New(fieldName + "长度或值不在合法范围," + rule)
					}
				}
			}
		}
	}
	return nil
}

// isBlank 非空校验
func isBlank(value reflect.Value) bool {
	switch value.Kind() {
	case reflect.String, reflect.Slice:
		return value.Len() == 0
	case reflect.Bool:
		return !value.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return value.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return value.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return value.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return value.IsNil()
	}
	return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}

// compareVerify 长度和数字的校验方法 根据类型自动校验
func compareVerify(value reflect.Value, VerifyStr string) bool {
	switch value.Kind() {
	case reflect.String:
		return compareInt(len([]rune(value.String())), VerifyStr)
	case reflect.Slice, reflect.Array:
		return compareInt(value.Len(), VerifyStr)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return compareUint(value.Uint(), VerifyStr)
	case reflect.Float32, reflect.Float64:
		return compareFloat64(value.Float(), VerifyStr)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return compareInt64(value.Int(), VerifyStr)
	default:
		return false
	}
}

// compareInt 整数比较
func compareInt(value int, VerifyStr string) bool {
	VerifyStrArr := strings.Split(VerifyStr, "=")
	VInt, VErr := strconv.Atoi(VerifyStrArr[1])
	if VErr != nil {
		return false
	}
	switch VerifyStrArr[0] {
	case "lt":
		return value < VInt
	case "le":
		return value <= VInt
	case "eq":
		return value == VInt
	case "ne":
		return value != VInt
	case "ge":
		return value >= VInt
	case "gt":
		return value > VInt
	default:
		return false
	}
}

// compareInt64 int64比较
func compareInt64(value int64, VerifyStr string) bool {
	VerifyStrArr := strings.Split(VerifyStr, "=")
	VInt, VErr := strconv.ParseInt(VerifyStrArr[1], 10, 64)
	if VErr != nil {
		return false
	}
	switch VerifyStrArr[0] {
	case "lt":
		return value < VInt
	case "le":
		return value <= VInt
	case "eq":
		return value == VInt
	case "ne":
		return value != VInt
	case "ge":
		return value >= VInt
	case "gt":
		return value > VInt
	default:
		return false
	}
}

// compareUint uint64比较
func compareUint(value uint64, VerifyStr string) bool {
	VerifyStrArr := strings.Split(VerifyStr, "=")
	VInt, VErr := strconv.ParseUint(VerifyStrArr[1], 10, 64)
	if VErr != nil {
		return false
	}
	switch VerifyStrArr[0] {
	case "lt":
		return value < VInt
	case "le":
		return value <= VInt
	case "eq":
		return value == VInt
	case "ne":
		return value != VInt
	case "ge":
		return value >= VInt
	case "gt":
		return value > VInt
	default:
		return false
	}
}

// compareFloat64 float64比较
func compareFloat64(value float64, VerifyStr string) bool {
	VerifyStrArr := strings.Split(VerifyStr, "=")
	VFloat, VErr := strconv.ParseFloat(VerifyStrArr[1], 64)
	if VErr != nil {
		return false
	}
	switch VerifyStrArr[0] {
	case "lt":
		return value < VFloat
	case "le":
		return value <= VFloat
	case "eq":
		return value == VFloat
	case "ne":
		return value != VFloat
	case "ge":
		return value >= VFloat
	case "gt":
		return value > VFloat
	default:
		return false
	}
}

// regexpMatch 正则匹配
func regexpMatch(rule, matchStr string) bool {
	return regexp.MustCompile(rule).MatchString(matchStr)
}
