package helper

import (
	"crypto/md5"
	"fmt"
	"github.com/golang/protobuf/proto"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"time"
)

func Log(name string, msg ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	timeLayout := "2006-01-01 03:04:05" //转化所需模板
	var datetime = time.Unix(time.Now().Unix(), 0).Format(timeLayout)
	fmt.Println(name, msg, file, line, datetime)
}

func LogErr(err error) {
	if err != nil {
		Log("err", err.Error())
	}
}

func Path(path string) (string, error) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		if err := os.MkdirAll(path, 0777); err != nil {
			return "", err
		}
	}
	return path, nil
}

func FileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	return err == nil || os.IsExist(err)
}

// TrackTime 运行时间  defer TrackTime()()
func TrackTime() func() {
	pre := time.Now()
	return func() {
		elapsed := time.Since(pre)
		fmt.Println("elapsed:", elapsed)
	}
}

// Ter 三目运算  Ter(true, 1, 2)
func Ter[T any](cond bool, a, b T) T {
	if cond {
		return a
	}
	return b
}

// get参转结构体
func ParseQueryStringToStruct(query string, target interface{}) error {
	// 解析查询字符串
	values, err := url.ParseQuery(query)
	if err != nil {
		return err
	}

	// 获取目标结构体的反射值
	rv := reflect.ValueOf(target).Elem()

	// 遍历查询字符串中的每个键值对
	for key, values := range values {
		// 假设每个查询参数只传递一个值(如果有多个值,这里只取第一个)
		value := values[0]

		// 查找目标结构体中对应的字段
		field := rv.FieldByName(strings.Title(key)) // 假设字段名与查询参数名相同,但首字母大写
		if !field.IsValid() || !field.CanSet() {
			// 如果找不到对应的字段,或者字段不可设置,则跳过
			continue
		}

		// 根据字段类型设置值
		switch field.Kind() {
		case reflect.String:
			field.SetString(value)
		case reflect.Int:
			intValue, err := strconv.Atoi(value)
			if err != nil {
				return err
			}
			field.SetInt(int64(intValue))
		// 可以根据需要添加更多类型处理
		default:
			// 不支持的类型,可以选择跳过或返回错误
			continue
		}
	}

	return nil
}

// GenerateMD5Hash 生成 MD5 的函数,接收一个实现了 proto.Message 接口的结构体
func GenerateMD5Hash(msg proto.Message) (string, error) {
	// 使用 proto.Marshal 序列化结构体,proto.Marshal 接受任何实现 proto.Message 接口的结构体
	data, err := proto.Marshal(msg)
	if err != nil {
		return "", fmt.Errorf("failed to serialize message: %v", err)
	}

	// 计算 MD5
	hash := md5.New()
	hash.Write(data)
	hashBytes := hash.Sum(nil)

	// 返回 MD5 值的十六进制字符串
	return fmt.Sprintf("%x", hashBytes), nil
}