package userstore

import (
	"context"
	"crypto/rand"
	"fmt"
	"strings"
)

const passwordAlphabet = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789"
const usernameAlphabet = "abcdefghijkmnopqrstuvwxyz23456789"
const usernameFirst = "abcdefghijkmnopqrstuvwxyz"

// RandomPassword 生成可读随机密码（不含易混字符 0/O/1/l）。
func RandomPassword(n int) (string, error) {
	if n < 8 {
		n = 12
	}
	b := make([]byte, n)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	out := make([]byte, n)
	for i := range b {
		out[i] = passwordAlphabet[int(b[i])%len(passwordAlphabet)]
	}
	return string(out), nil
}

// RandomUsername 生成随机登录名（字母开头，仅小写字母与数字，默认 10 位）。
func RandomUsername() (string, error) {
	const n = 10
	b := make([]byte, n)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	out := make([]byte, n)
	out[0] = usernameFirst[int(b[0])%len(usernameFirst)]
	for i := 1; i < n; i++ {
		out[i] = usernameAlphabet[int(b[i])%len(usernameAlphabet)]
	}
	return string(out), nil
}

// AllocUniqueUsername 分配全局唯一随机用户名。
func AllocUniqueUsername(ctx context.Context, exists func(context.Context, string) (bool, error)) (string, error) {
	var last error
	for i := 0; i < 16; i++ {
		u, err := RandomUsername()
		if err != nil {
			return "", err
		}
		ok, err := exists(ctx, u)
		if err != nil {
			return "", err
		}
		if ok {
			last = fmt.Errorf("username collision")
			continue
		}
		return u, nil
	}
	if last != nil {
		return "", fmt.Errorf("无法生成唯一用户名: %v", last)
	}
	return "", fmt.Errorf("无法生成唯一用户名")
}

// Deprecated: 保留测试兼容；新逻辑请用 RandomUsername / AllocUniqueUsername。
func SuggestAdminUsername(slug string) string {
	s := strings.ToLower(strings.TrimSpace(slug))
	var b strings.Builder
	for _, r := range s {
		if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') {
			b.WriteRune(r)
		}
	}
	base := b.String()
	if base == "" {
		base = "co"
	}
	if len(base) > 20 {
		base = base[:20]
	}
	return base + "_adm"
}

// Deprecated: 见 AllocUniqueUsername。
func NextUsernameCandidate(base string, attempt int) string {
	base = strings.TrimSpace(base)
	if base == "" {
		base = "user"
	}
	if attempt <= 0 {
		return base
	}
	suffix, err := RandomPassword(4)
	if err != nil {
		return fmt.Sprintf("%s%d", base, attempt)
	}
	return fmt.Sprintf("%s_%s", base, strings.ToLower(suffix))
}
