package utils

import (
	"encoding/json"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/civet148/gotools/randoms"

	"github.com/mssola/user_agent"
)

// 验证码位数
const AuthCodeNum = 6

const (
	UNIT_EiB     = "EiB"
	UNIT_PIB     = "PiB"
	UNIT_DOLLAR  = "$"
	UNIT_BILLION = "billion"
)

const (
	UNIT_ALL = UNIT_EiB + "|" + UNIT_PIB + "|" + UNIT_DOLLAR + "|" + UNIT_BILLION
)

func JsonMarshal(v interface{}) string {
	var data []byte
	data, _ = json.Marshal(v)
	return string(data)
}

func MakeTimestampSuffix(strKey string) string {
	now := time.Now().Unix()
	return fmt.Sprintf("%s_%d", strKey, now)
}

func ConvertFloat64NonUnit(strNumber string) float64 {
	units := strings.Split(UNIT_ALL, "|")
	for _, unit := range units {
		strNumber = strings.Replace(strNumber, unit, "", -1)
	}
	strNumber = strings.TrimSpace(strNumber)
	number, err := strconv.ParseFloat(strNumber, 64)
	if err != nil {
		fmt.Printf("parse float (%s) error [%s]", strNumber, err)
		return 0
	}
	return number
}

func CheckDurationMinutes(strDuration string) (ok bool, minutes int64, err error) {
	if strings.Contains(strDuration, "m") {
		ok = true
		strMinutes := strings.TrimSuffix(strDuration, "m")
		minutes, err = strconv.ParseInt(strMinutes, 10, 32)
	}
	return
}

func CheckDurationHours(strDuration string) (ok bool, hours int64, err error) {
	if strings.Contains(strDuration, "h") {
		ok = true
		strHours := strings.TrimSuffix(strDuration, "h")
		hours, err = strconv.ParseInt(strHours, 10, 32)
	}
	return
}

func ParseUserAgent(userAgent string) (osi user_agent.OSInfo, isMobile bool) {
	ua := user_agent.New(userAgent)
	return ua.OSInfo(), ua.Mobile()
}

func StructToMap(s interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	valueOf := reflect.ValueOf(s)
	typeOf := reflect.TypeOf(s)

	for i := 0; i < valueOf.NumField(); i++ {
		fieldValue := valueOf.Field(i)
		fieldName := typeOf.Field(i).Name
		result[fieldName] = fieldValue.Interface()
	}
	return result
}

func GenAuthCode() (code string) {
	return randoms.RandomAlphaOrNumeric(AuthCodeNum, false, true)
}

// GetMBUUID 尝试从系统中获取主板/系统唯一标识符（适用于 Linux）
func GetMBUUID() string {
	paths := []string{
		"/sys/class/dmi/id/product_uuid",   // 系统 UUID
		"/sys/class/dmi/id/product_serial", // 系统序列号
		"/sys/class/dmi/id/board_serial",   // 主板序列号
		"/sys/class/dmi/id/chassis_serial", // 机箱序列号
		"/etc/machine-id",                  // fallback
	}

	for _, path := range paths {
		if val, ok := readAndValidateHardwareID(path); ok {
			return val
		}
	}
	return "unknown"
}

// readAndValidateHardwareID 从文件中读取并验证内容是否是有效硬件ID
func readAndValidateHardwareID(path string) (string, bool) {
	data, err := os.ReadFile(path)
	if err != nil {
		return "", false
	}
	val := strings.TrimSpace(string(data))
	lower := strings.ToLower(val)

	if val == "" ||
		strings.Contains(lower, "to be filled") ||
		strings.Contains(lower, "not specified") ||
		strings.Contains(lower, "default") ||
		lower == "ffffffff-ffff-ffff-ffff-ffffffffffff" {
		return "", false
	}
	return val, true
}
