package tool

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"reflect"
	"runtime"
	"strings"
	"time"
	"unicode"
	"unsafe"

	"github.com/mozillazg/go-pinyin"
	"google.golang.org/grpc/status"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

// 各种工具方法放这里

// SnakeString 驼峰转蛇形
func SnakeString(s string) string {
	data := make([]byte, 0, len(s)*2)
	j := false
	num := len(s)
	for i := 0; i < num; i++ {
		d := s[i]
		// or通过ASCII码进行大小写的转化
		// 65-90（A-Z），97-122（a-z）
		// 判断如果字母为大写的A-Z就在前面拼接一个_
		if i > 0 && d >= 'A' && d <= 'Z' && j {
			data = append(data, '_')
		}
		if d != '_' {
			j = true
		}
		data = append(data, d)
	}
	// ToLower把大写字母统一转小写
	return strings.ToLower(string(data[:]))
}

// CamelString 蛇形转驼峰
func CamelString(s string) string {
	data := make([]byte, 0, len(s))
	j := false
	k := false
	num := len(s) - 1
	for i := 0; i <= num; i++ {
		d := s[i]
		if k == false && d >= 'A' && d <= 'Z' {
			k = true
		}
		if d >= 'a' && d <= 'z' && (j || k == false) {
			d = d - 32
			j = false
			k = true
		}
		if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
			j = true
			continue
		}
		data = append(data, d)
	}
	return string(data[:])
}

func loadTLSCredentials() (credentials.TransportCredentials, error) {
	// Load server's certificate and private key
	serverCert, err := tls.LoadX509KeyPair("../cert/server-cert.pem", "../cert/server-key.pem")
	if err != nil {
		return nil, err
	}

	// Create the credentials and return it
	config := &tls.Config{
		Certificates: []tls.Certificate{serverCert},
		ClientAuth:   tls.NoClientCert,
	}

	return credentials.NewTLS(config), nil
}

// 服务启动的时候 获取版本号
func GetRelease(opts []grpc.ServerOption) (string, *grpc.Server) {
	releaseS := os.Getenv("release")
	gS := grpc.NewServer()
	if len(opts) > 0 {
		gS = grpc.NewServer(opts...)
	}

	loacl_ip, err := GetLocalIp()
	if err != nil {
		fmt.Println(err)
	}
	if releaseS != "v2" && releaseS != "test" && releaseS != "develop" {
		return loacl_ip, gS
	} else {
		// 正式服 需要认证
		// tlsCredentials, err := loadTLSCredentials()
		// if err != nil {
		//	log.Fatal("不能加载tls认证 ", err)
		// }
		// opts = append(opts, grpc.Creds(tlsCredentials))
		// gS = grpc.NewServer(opts)
	}

	return loacl_ip, gS
}

// GetExcelColumnName 通过列数获取excel的列名称，用于excel导出数据使用
func GetExcelColumnName(columnIndex int32) string {
	var (
		columns          = make([]string, 0, 26)
		columnNameArr    []string
		reverseColumnArr []string
	)
	for s := 'A'; s <= 'Z'; s++ {
		columns = append(columns, string(s))
	}

	for {
		m := columnIndex % 26
		if m <= 0 {
			m = 26
		}
		columnNameArr = append(columnNameArr, columns[m-1])
		columnIndex = (columnIndex - m) / 26
		if columnIndex <= 0 {
			break
		}
	}

	for i := len(columnNameArr) - 1; i >= 0; i-- {
		reverseColumnArr = append(reverseColumnArr, columnNameArr[i])
	}
	return strings.Join(reverseColumnArr, ``)
}

// ParseTokenWithAes256 模拟Phalcon解密token
// func ParseTokenWithAes256(token, key string) ([]byte, error) {
//	decryptString, err := base64x.JSONStdEncoding.DecodeString(token)
//	if err != nil {
//		return nil, fmt.Errorf(`base64_decode: %#v`, err)
//	}
//	k := make([]byte, 32)
//	ky := []byte(key)
//	for i, v := range ky {
//		k[i] = v
//	}
//	cb, err := aes.NewCipher(k)
//	if err != nil {
//		return nil, fmt.Errorf(`aes.NewCipher: %v`, err)
//	}
//	var resp = make([]byte, len(decryptString[16:]))
//	cipher.NewCFBDecrypter(cb, decryptString[0:16]).XORKeyStream(resp, decryptString[16:])
//
//	return resp, nil
// }

// 如果用了网关，不要在代码实现可以
func Cors() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")                                                            // 允许访问所有域，可以换成具体url，注意仅具体url才能带cookie信息
		w.Header().Add("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") // header的类型
		w.Header().Add("Access-Control-Allow-Credentials", "true")                                                    // 设置为true，允许ajax异步请求带cookie信息
		w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")                             // 允许请求方法
		w.Header().Set("content-type", "application/json;charset=UTF-8")                                              // 返回数据格式是json
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusOK)
			return
		}
	}
}

// GetCallFunc 获取调用者的方法名称
func GetCallFunc(caller int) string {
	pc, _, _, _ := runtime.Caller(caller)
	return runtime.FuncForPC(pc).Name()
}

// ChinesConvertPinyin 中文转拼音(支持大写)
func ChinesConvertPinyin(s string, uppercase bool) (py []string) {
	newPy := pinyin.NewArgs()
	for _, r := range s {
		if unicode.Is(unicode.Han, r) {
			singlePy := pinyin.SinglePinyin(r, newPy)
			py = append(py, singlePy...)
		} else {
			singlePy := string(r)
			py = append(py, singlePy)
		}
	}
	if uppercase {
		pyStr := strings.Join(py, " ")
		pyStr = strings.ToUpper(pyStr)
		return strings.Split(pyStr, " ")
	}
	return
}

// GetStrPointerVal 获取字符串指针的值
func GetStrPointerVal(str *string) (resp string) {
	resp = ""
	if str != nil {
		resp = *str
	}
	return
}

// ToLowerFirstSting 首字母小写
func ToLowerFirstSting(s string) string {
	if s == "" {
		return ""
	}
	rs := []rune(s)
	rs[0] = unicode.ToLower(rs[0])
	return string(rs)
}

// ToUpperFirstSting 首字母大写
func ToUpperFirstSting(s string) string {
	if s == "" {
		return ""
	}
	rs := []rune(s)
	rs[0] = unicode.ToUpper(rs[0])
	return string(rs)
}

// ReplaceAllBySliceSting 批量替换
func ReplaceAllBySliceSting(s string, old []string, new []string) string {
	if s == "" {
		return ""
	}
	for i, v := range old {
		if len(new) == 1 {
			s = strings.ReplaceAll(s, v, new[0])
		} else {
			s = strings.ReplaceAll(s, v, new[i])
		}
	}
	return s
}

// LowerFirst 首字母小写
func LowerFirst(str string) string {
	if str == `` {
		return ``
	}
	if unicode.IsLower(rune(str[0])) {
		return str
	}

	return string(unicode.ToLower(rune(str[0]))) + str[1:]
}

// ToSnake 字符串函数将驼峰转为下划线
func ToSnake(s string) string {
	var b strings.Builder

	for i, c := range s {
		switch {
		case c >= 'A' && c <= 'Z':
			if i != 0 {
				b.WriteByte('_')
			}
			c ^= 0x20
			b.WriteRune(c)
		default:
			b.WriteRune(c)
		}
	}

	return b.String()
}

// ToCamel 字符串函数将下划线转为驼峰
func ToCamel(s string) string {
	var b strings.Builder

	var upperNext = false
	for _, c := range s {
		switch {
		case c == '_':
			upperNext = true
			continue
		case upperNext:
			if c >= 'a' && c <= 'z' {
				c ^= 0x20
			}
			upperNext = false
		}
		b.WriteRune(c)
	}

	return b.String()
}

func Ternary[T any](exp bool, trueVal, falseVal T) T {
	if exp {
		return trueVal
	}
	return falseVal

}

// SetTimeout 设置超时时间
func SetTimeout(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
	var cancel context.CancelFunc
	if _, isSet := ctx.Deadline(); !isSet {
		ctx, cancel = context.WithTimeout(ctx, timeout)
	}
	return ctx, cancel
}

func CountEmptyFields(obj interface{}, fieldNames []string) int {
	count := 0

	objValue := reflect.ValueOf(obj).Elem()
	objType := objValue.Type()

	if len(fieldNames) == 0 {
		for i := 0; i < objValue.NumField(); i++ {
			fieldType := objType.Field(i)
			fieldNames = append(fieldNames, fieldType.Name)
		}
	}

	// 遍历对象的字段
	for _, fieldName := range fieldNames {
		// 获取字段的值
		fieldValue := objValue.FieldByName(fieldName)
		if !fieldValue.IsValid() {
			continue
		}

		// 检查字段是否为指针
		fieldType := fieldValue.Type()
		if fieldValue.Kind() == reflect.Ptr {
			if fieldValue.IsNil() || (fieldType.Elem().Kind() == reflect.String && fieldValue.Elem().String() == "") {
				count++
			}
			continue
		}

		// 非指针字段判断是否为零值
		if !fieldValue.CanInterface() {
			// 获取未导出字段的值
			fieldValue = reflect.NewAt(fieldType, unsafe.Pointer(fieldValue.UnsafeAddr())).Elem()
		}

		zeroValue := reflect.Zero(fieldType)
		if reflect.DeepEqual(fieldValue.Interface(), zeroValue.Interface()) {
			count++
		}
	}

	return count
}

// GetErrorMessage 获取明细
func GetErrorMessage(err error) string {
	if v, ok := status.FromError(err); ok {
		return v.Message()
	}
	return err.Error()
}

func Assert[T any](v any, defaultValue T) T {
	if value, ok := v.(T); ok {
		return value
	}
	return defaultValue
}
