package tools

import (
	"context"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"math/big"
	mathrand "math/rand"
	"strings"
)

// RandomTool provides random generation utilities for the LLM.
// Supports random numbers, UUIDs, passwords, and list operations.
type RandomTool struct{}

// NewRandomTool creates a random generation tool.
func NewRandomTool() *RandomTool {
	return &RandomTool{}
}

// Definition returns the tool definition for LLM function calling.
func (t *RandomTool) Definition() ToolDefinition {
	return ToolDefinition{
		Name:        "random",
		Description: "随机生成工具。生成随机数、UUID、安全密码，或从列表中随机选取/打乱元素。",
		Parameters: map[string]interface{}{
			"type": "object",
			"properties": map[string]interface{}{
				"action": map[string]interface{}{
					"type":        "string",
					"enum":        []string{"number", "uuid", "password", "pick", "shuffle"},
					"description": "操作类型。number: 生成随机整数；uuid: 生成UUID v4；password: 生成安全密码；pick: 从列表随机选取；shuffle: 随机打乱列表",
				},
				"min": map[string]interface{}{
					"type":        "number",
					"description": "随机数最小值（用于 number 操作），默认 0",
				},
				"max": map[string]interface{}{
					"type":        "number",
					"description": "随机数最大值（用于 number 操作），默认 100",
				},
				"length": map[string]interface{}{
					"type":        "integer",
					"description": "密码长度（用于 password 操作），默认 16",
				},
				"items": map[string]interface{}{
					"type":        "array",
					"description": "列表项（用于 pick/shuffle 操作），字符串数组",
					"items": map[string]interface{}{
						"type": "string",
					},
				},
				"count": map[string]interface{}{
					"type":        "integer",
					"description": "选取数量（用于 pick 操作），默认 1",
				},
			},
			"required": []string{"action"},
		},
	}
}

// Execute performs random generation operations.
func (t *RandomTool) Execute(ctx context.Context, arguments map[string]interface{}) (*ToolResult, error) {
	action, ok := arguments["action"].(string)
	if !ok || action == "" {
		return &ToolResult{
			ToolName: "random",
			Success:  false,
			Error:    "缺少 action 参数",
		}, nil
	}

	switch action {
	case "number":
		return t.handleNumber(arguments)
	case "uuid":
		return t.handleUUID()
	case "password":
		return t.handlePassword(arguments)
	case "pick":
		return t.handlePick(arguments)
	case "shuffle":
		return t.handleShuffle(arguments)
	default:
		return &ToolResult{
			ToolName: "random",
			Success:  false,
			Error:    fmt.Sprintf("未知操作: %s，支持: number, uuid, password, pick, shuffle", action),
		}, nil
	}
}

// handleNumber generates a random integer in [min, max].
func (t *RandomTool) handleNumber(arguments map[string]interface{}) (*ToolResult, error) {
	minVal := getFloatArg(arguments, "min", 0)
	maxVal := getFloatArg(arguments, "max", 100)

	if minVal > maxVal {
		minVal, maxVal = maxVal, minVal
	}

	minI := int64(minVal)
	maxI := int64(maxVal)

	// Use crypto/rand for secure random
	rangeVal := maxI - minI + 1
	if rangeVal <= 0 {
		return &ToolResult{
			ToolName: "random",
			Success:  false,
			Error:    "无效的数值范围",
		}, nil
	}

	n, err := rand.Int(rand.Reader, big.NewInt(rangeVal))
	if err != nil {
		// Fallback to math/rand
		result := minI + mathrand.Int63n(rangeVal)
		return &ToolResult{
			ToolName: "random",
			Success:  true,
			Data:     fmt.Sprintf("随机整数 [%d, %d]: %d", minI, maxI, result),
		}, nil
	}

	result := minI + n.Int64()
	return &ToolResult{
		ToolName: "random",
		Success:  true,
		Data:     fmt.Sprintf("随机整数 [%d, %d]: %d", minI, maxI, result),
	}, nil
}

// handleUUID generates a UUID v4 string.
func (t *RandomTool) handleUUID() (*ToolResult, error) {
	uuid := make([]byte, 16)
	_, err := rand.Read(uuid)
	if err != nil {
		return &ToolResult{
			ToolName: "random",
			Success:  false,
			Error:    fmt.Sprintf("生成UUID失败: %v", err),
		}, nil
	}

	// Set version 4 and variant bits
	uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
	uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant 10

	uuidStr := fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
		uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])

	return &ToolResult{
		ToolName: "random",
		Success:  true,
		Data:     fmt.Sprintf("UUID v4: %s", uuidStr),
	}, nil
}

// handlePassword generates a secure random password.
func (t *RandomTool) handlePassword(arguments map[string]interface{}) (*ToolResult, error) {
	length := getIntArg(arguments, "length", 16)
	if length < 4 {
		length = 16
	}
	if length > 128 {
		length = 128
	}

	uppercase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	lowercase := "abcdefghijklmnopqrstuvwxyz"
	digits := "0123456789"
	symbols := "!@#$%^&*()_+-=[]{}|;:,.<>?"

	allChars := uppercase + lowercase + digits + symbols

	password := make([]byte, length)

	// Ensure at least one of each character type
	password[0] = uppercase[secureIndex(len(uppercase))]
	password[1] = lowercase[secureIndex(len(lowercase))]
	password[2] = digits[secureIndex(len(digits))]
	password[3] = symbols[secureIndex(len(symbols))]

	// Fill remaining with random characters from all sets
	for i := 4; i < length; i++ {
		password[i] = allChars[secureIndex(len(allChars))]
	}

	// Shuffle the password
	shuffleBytes(password)

	passwordStr := string(password)

	return &ToolResult{
		ToolName: "random",
		Success:  true,
		Data: fmt.Sprintf("安全密码 (长度: %d):\n%s\n\n字符集: 大写字母 + 小写字母 + 数字 + 特殊符号",
			length, passwordStr),
	}, nil
}

// handlePick randomly picks items from a list.
func (t *RandomTool) handlePick(arguments map[string]interface{}) (*ToolResult, error) {
	items := getStringSliceArg(arguments, "items")
	if len(items) == 0 {
		return &ToolResult{
			ToolName: "random",
			Success:  false,
			Error:    "缺少 items 参数或列表为空",
		}, nil
	}

	count := getIntArg(arguments, "count", 1)
	if count < 1 {
		count = 1
	}
	if count > len(items) {
		count = len(items)
	}

	// Shuffle indices and pick first 'count'
	indices := make([]int, len(items))
	for i := range indices {
		indices[i] = i
	}
	shuffleInts(indices)

	picked := make([]string, 0, count)
	for i := 0; i < count; i++ {
		picked = append(picked, items[indices[i]])
	}

	var result strings.Builder
	result.WriteString(fmt.Sprintf("从 %d 个选项中随机选取 %d 个:\n", len(items), count))
	for i, p := range picked {
		result.WriteString(fmt.Sprintf("  %d. %s\n", i+1, p))
	}

	return &ToolResult{
		ToolName: "random",
		Success:  true,
		Data:     result.String(),
	}, nil
}

// handleShuffle randomly shuffles a list.
func (t *RandomTool) handleShuffle(arguments map[string]interface{}) (*ToolResult, error) {
	items := getStringSliceArg(arguments, "items")
	if len(items) == 0 {
		return &ToolResult{
			ToolName: "random",
			Success:  false,
			Error:    "缺少 items 参数或列表为空",
		}, nil
	}

	// Make a copy and shuffle
	shuffled := make([]string, len(items))
	copy(shuffled, items)
	shuffleStrings(shuffled)

	var result strings.Builder
	result.WriteString(fmt.Sprintf("随机打乱结果 (共 %d 项):\n", len(shuffled)))
	for i, s := range shuffled {
		result.WriteString(fmt.Sprintf("  %d. %s\n", i+1, s))
	}

	return &ToolResult{
		ToolName: "random",
		Success:  true,
		Data:     result.String(),
	}, nil
}

// --- Helper functions ---

// getFloatArg extracts a float64 argument with fallback.
func getFloatArg(arguments map[string]interface{}, key string, fallback float64) float64 {
	if v, ok := arguments[key]; ok {
		switch val := v.(type) {
		case float64:
			return val
		case int:
			return float64(val)
		case int64:
			return float64(val)
		case json.Number:
			f, err := val.Float64()
			if err == nil {
				return f
			}
		}
	}
	return fallback
}

// getIntArg extracts an int argument with fallback.
func getIntArg(arguments map[string]interface{}, key string, fallback int) int {
	if v, ok := arguments[key]; ok {
		switch val := v.(type) {
		case float64:
			return int(val)
		case int:
			return val
		case int64:
			return int(val)
		}
	}
	return fallback
}

// getStringSliceArg extracts a string slice argument.
func getStringSliceArg(arguments map[string]interface{}, key string) []string {
	if v, ok := arguments[key]; ok {
		switch val := v.(type) {
		case []interface{}:
			result := make([]string, 0, len(val))
			for _, item := range val {
				if s, ok := item.(string); ok {
					result = append(result, s)
				} else {
					result = append(result, fmt.Sprintf("%v", item))
				}
			}
			return result
		case []string:
			return val
		}
	}
	return nil
}

// secureIndex returns a cryptographically secure random index in [0, max).
func secureIndex(max int) int {
	if max <= 1 {
		return 0
	}
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
	if err != nil {
		return mathrand.Intn(max)
	}
	return int(n.Int64())
}

// shuffleBytes shuffles a byte slice using Fisher-Yates with crypto/rand.
func shuffleBytes(data []byte) {
	for i := len(data) - 1; i > 0; i-- {
		j := secureIndex(i + 1)
		data[i], data[j] = data[j], data[i]
	}
}

// shuffleInts shuffles an int slice using Fisher-Yates with crypto/rand.
func shuffleInts(data []int) {
	for i := len(data) - 1; i > 0; i-- {
		j := secureIndex(i + 1)
		data[i], data[j] = data[j], data[i]
	}
}

// shuffleStrings shuffles a string slice using Fisher-Yates with crypto/rand.
func shuffleStrings(data []string) {
	for i := len(data) - 1; i > 0; i-- {
		j := secureIndex(i + 1)
		data[i], data[j] = data[j], data[i]
	}
}
