package comfunc

import (
	
	
	
	
	
	
)

var (
	// check is duration string. TIP: extend unit d,w.  eg: "1d", "2w"
	//
	// time.ParseDuration() is max support hour "h".
	durStrReg = regexp.MustCompile(`^-?([0-9]+(?:\.[0-9]*)?(ns|us|µs|ms|s|m|h|d|w))+$`)

	// check long duration string. 验证整体格式是否符合
	//
	// eg: "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks", "1month"
	//
	// time.ParseDuration() is not support long unit.
	durStrRegL = regexp.MustCompile(`^-?([0-9]+(?:\.[0-9]*)?[nuµsmhdw][a-zA-Z]{0,8})+$`)
	// use for parse duration string. see ToDuration()
	//
	// NOTE: 解析时,不能加最后的 `+` 会导致只匹配了最后一组 时间单位
	durStrRegL2 = regexp.MustCompile(`-?([0-9]+(?:\.[0-9]*)?)([nuµsmhdw][a-z]{0,8})`)
)

// IsDuration check the string is a duration string.
func ( string) bool {
	if  == "0" || durStrReg.MatchString() {
		return true
	}
	return durStrRegL.MatchString()
}

// ToDuration parses a duration string. such as "300ms", "-1.5h" or "2h45m".
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
//
// Diff of time.ParseDuration:
//   - support extends unit d, w at the end of string. such as "1d", "2w".
//   - support extends unit: month, week, day
//   - support long string unit at the end. such as "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks".
//
// If the string is not a valid duration string, it will return an error.
func ( string) (time.Duration, error) {
	 := len()
	if  == 0 {
		return 0, fmt.Errorf("empty duration string")
	}

	 = strings.ToLower()
	if  == "0" {
		return 0, nil
	}

	// check duration string is valid
	if !durStrRegL.MatchString() {
		return 0, fmt.Errorf("invalid duration string: %s", )
	}

	// if ln < 4 AND end != d|w, directly call time.ParseDuration()
	if  < 4 && [-1] != 'd' && [-1] != 'w' {
		return time.ParseDuration()
	}

	// time.ParseDuration() is not support long unit.
	 := durStrRegL2.FindAllStringSubmatch(, -1)
	// fmt.Println(ssList)
	 := make([]byte, 0, )
	if [0] == '-' {
		 = append(, '-')
	}

	// only one element. eg: "1day"
	if len() == 1 {
		 = parseLongUnit([0], )
	} else {
		// more than one element. eg: "1day2hour3min"
		for ,  := range  {
			if len() == 3 {
				 = parseLongUnit(, )
			}
		}
	}

	return time.ParseDuration(string())
}

// convert to short unit
func parseLongUnit( []string,  []byte) []byte {
	// eg: "3sec" -> ss=[3sec, -3, sec]
	,  := [1], [2]
	switch  {
	case "month", "months":
		// time lib max unit is hour, so need convert by 24 * 30*n
		 = appendNumToBytes(, , 24*30)
		 = append(, 'h')
	case "w", "week", "weeks":
		// time lib max unit is hour, so need convert by 24 * 7*n
		 = appendNumToBytes(, , 24*7)
		 = append(, 'h')
	case "d", "day", "days":
		// time lib max unit is hour, so need convert by 24*n
		 = appendNumToBytes(, , 24)
		 = append(, 'h')
	case "hour", "hours":
		 = append(, ...)
		 = append(, 'h')
	case "min", "mins", "minute", "minutes":
		 = append(, ...)
		 = append(, 'm')
	case "sec", "secs", "second", "seconds":
		 = append(, ...)
		 = append(, 's')
	default:
		 := [0]

		// '-' has been added on ToDuration()
		if [0] == '-' {
			 = append(, [1:]...)
		} else {
			 = append(, ...)
		}
	}

	return 
}

func appendNumToBytes( []byte,  string,  int) []byte {
	if strings.ContainsRune(, '.') {
		,  := strconv.ParseFloat(, 64) // is float number
		 :=  * float64()

		// 使用 Float 保留两位小数 -> 会始终有两位小数,即使是N.00
		// bts = strconv.AppendFloat(bts, val, 'f', 2, 64)

		// 四舍五入到两位小数
		 := math.Round(*100) / 100
		// 使用 AppendFloat 自动去除末尾的 .0 或 .00
		 = strconv.AppendFloat(, , 'f', -1, 64)
	} else {
		,  := strconv.Atoi()
		 = strconv.AppendInt(, int64(*), 10)
	}

	return 
}