package otherutils

import (
	"bytes"
	"fmt"
	"math/rand"
	"strings"
	"sync/atomic"
	"time"
)

const (
	charset     = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	maxBase     = 62
	defaultBase = 61
	maxOrderNum = 65536
)

var orderIncrId uint32 // 订单自增ID，每次重启从头开始即可

// ConvertToBaseN converts a decimal number to a string representation in the specified base (2-62)
func ConvertToBaseN(decimalNum int64, base int64) (string, error) {
	if base <= 0 || base > maxBase {
		return "", fmt.Errorf("base must be between 1 and %d", maxBase)
	}
	if decimalNum == 0 {
		return "0", nil
	}
	if decimalNum < 0 {
		return "", fmt.Errorf("negative numbers are not supported")
	}

	var buf bytes.Buffer
	for decimalNum > 0 {
		remainder := decimalNum % base
		decimalNum /= base
		buf.WriteByte(charset[remainder])
	}

	// Reverse the result
	result := buf.Bytes()
	for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
		result[i], result[j] = result[j], result[i]
	}
	return string(result), nil
}

// ConvertToDecimal converts a string in the specified base (2-62) to decimal
func ConvertToDecimal(str string, base int64) (int64, error) {
	if base <= 0 || base > maxBase {
		return 0, fmt.Errorf("base must be between 1 and %d", maxBase)
	}
	if str == "" {
		return 0, fmt.Errorf("empty string is not valid")
	}

	var result int64
	for i, char := range str {
		index := strings.IndexRune(charset, char)
		if index == -1 || index >= int(base) {
			return 0, fmt.Errorf("invalid character '%c' for base %d", char, base)
		}
		// Use multiplication instead of math.Pow to avoid floating point precision issues
		power := len(str) - i - 1
		multiplier := int64(1)
		for j := 0; j < power; j++ {
			multiplier *= base
		}
		result += int64(index) * multiplier
	}
	return result, nil
}

// formatDateTime returns a compact string representation of the current time
func formatDateTime(t time.Time) int64 {
	y, m, d := t.Date()
	h, mi, s := t.Hour(), t.Minute(), t.Second()
	return int64(y)*1e10 + int64(m)*1e8 + int64(d)*1e6 + int64(h)*1e4 + int64(mi)*1e2 + int64(s)
}

// CreateOutTradeNo generates a unique trade number
func CreateOutTradeNo(playerId int64, serverId int64, zoneId int) string {
	n := atomic.AddUint32(&orderIncrId, 1) % maxOrderNum
	num := formatDateTime(time.Now())

	baseN, _ := ConvertToBaseN(num, defaultBase)
	serverIdStr, _ := ConvertToBaseN(serverId, defaultBase)
	playerIdStr, _ := ConvertToBaseN(playerId, defaultBase)
	orderStr, _ := ConvertToBaseN(int64(n), defaultBase)

	return fmt.Sprintf("%sZ%sZ%sZ%sZ%d",
		baseN, serverIdStr, playerIdStr, orderStr, zoneId)
}

func TestCreateOutTradeNo() {
	var (
		playerId = 1
		serverId = 102
		zoneId   = 1
	)

	for i := 0; i < 10000; i += 1 {
		playerId += 10000000
		orderCode := CreateOutTradeNo(int64(playerId), int64(serverId), zoneId)
		fmt.Println(orderCode)
	}
}

// 随机不含重复字符的字符串
// l长度 超过20需修改逻辑 命中会降低
func RandString(l int) string {
	cl := len(charset)
	if l > cl || l <= 0 {
		return ""
	}

	bytes := make([]byte, l)
	selected := make(map[byte]bool)

	for i := 0; i < l; {
		b := rand.Intn(cl)
		char := charset[b]

		if !selected[char] {
			bytes[i] = char
			selected[char] = true
			i++
		}
	}

	return string(bytes)
}
