package tools

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

// JSONTool provides JSON parsing, querying, and validation for the LLM.
type JSONTool struct{}

// NewJSONTool creates a JSON processing tool.
func NewJSONTool() *JSONTool {
	return &JSONTool{}
}

// Definition returns the tool definition for LLM function calling.
func (t *JSONTool) Definition() ToolDefinition {
	return ToolDefinition{
		Name:        "json_ops",
		Description: "JSON处理工具。解析JSON字符串并格式化输出、用简单路径查询JSON字段、验证JSON是否合法。",
		Parameters: map[string]interface{}{
			"type": "object",
			"properties": map[string]interface{}{
				"action": map[string]interface{}{
					"type":        "string",
					"enum":        []string{"parse", "query", "validate"},
					"description": "操作类型。parse: 解析JSON并格式化输出；query: 用路径查询JSON中的值（如\"users.0.name\"表示取users数组第0个元素的name字段）；validate: 验证JSON字符串是否合法",
				},
				"json_string": map[string]interface{}{
					"type":        "string",
					"description": "JSON字符串",
				},
				"path": map[string]interface{}{
					"type":        "string",
					"description": "查询路径（query操作时使用）。支持点分隔和数组索引，如 \"users.0.name\"、\"data.list.2.title\"",
				},
			},
			"required": []string{"action", "json_string"},
		},
	}
}

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

	jsonStr, ok := arguments["json_string"].(string)
	if !ok || jsonStr == "" {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    "缺少 json_string 参数",
		}, nil
	}

	switch action {
	case "parse":
		return t.handleParse(jsonStr)
	case "query":
		path, _ := arguments["path"].(string)
		return t.handleQuery(jsonStr, path)
	case "validate":
		return t.handleValidate(jsonStr)
	default:
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    fmt.Sprintf("未知操作: %s，支持: parse, query, validate", action),
		}, nil
	}
}

// handleParse parses a JSON string and returns a formatted version.
func (t *JSONTool) handleParse(jsonStr string) (*ToolResult, error) {
	var data interface{}
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    fmt.Sprintf("JSON解析失败: %v", err),
		}, nil
	}

	pretty, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    fmt.Sprintf("JSON格式化失败: %v", err),
		}, nil
	}

	return &ToolResult{
		ToolName: "json_ops",
		Success:  true,
		Data:     fmt.Sprintf("解析成功\n格式化输出:\n%s", string(pretty)),
	}, nil
}

// handleQuery queries a JSON value by dot-notation path.
func (t *JSONTool) handleQuery(jsonStr, path string) (*ToolResult, error) {
	if path == "" {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    "query 操作需要 path 参数",
		}, nil
	}

	var data interface{}
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    fmt.Sprintf("JSON解析失败: %v", err),
		}, nil
	}

	value, err := queryPath(data, path)
	if err != nil {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  false,
			Error:    err.Error(),
		}, nil
	}

	pretty, err := json.MarshalIndent(value, "", "  ")
	if err != nil {
		return &ToolResult{
			ToolName: "json_ops",
			Success:  true,
			Data:     fmt.Sprintf("路径: %s\n值: %v", path, value),
		}, nil
	}

	return &ToolResult{
		ToolName: "json_ops",
		Success:  true,
		Data:     fmt.Sprintf("路径: %s\n值:\n%s", path, string(pretty)),
	}, nil
}

// handleValidate validates whether a string is valid JSON.
func (t *JSONTool) handleValidate(jsonStr string) (*ToolResult, error) {
	var data interface{}
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		// Try to give a helpful error message
		errStr := err.Error()
		// Extract line/position info if available
		return &ToolResult{
			ToolName: "json_ops",
			Success:  true,
			Data:     fmt.Sprintf("❌ JSON不合法\n错误: %s", errStr),
		}, nil
	}

	// Determine JSON type
	typeName := "object"
	switch data.(type) {
	case []interface{}:
		typeName = "array"
	case string:
		typeName = "string"
	case float64:
		typeName = "number"
	case bool:
		typeName = "boolean"
	case nil:
		typeName = "null"
	}

	size := len(jsonStr)
	return &ToolResult{
		ToolName: "json_ops",
		Success:  true,
		Data:     fmt.Sprintf("✅ JSON合法\n类型: %s\n大小: %d bytes", typeName, size),
	}, nil
}

// queryPath traverses a JSON value using dot-notation and array index syntax.
// Examples: "users.0.name", "data.list", "items.2"
func queryPath(data interface{}, path string) (interface{}, error) {
	// Remove leading "$." if present (JSONPath style)
	path = strings.TrimPrefix(path, "$.")
	if path == "" || path == "$" {
		return data, nil
	}

	parts := strings.Split(path, ".")
	current := data

	for _, part := range parts {
		switch v := current.(type) {
		case map[string]interface{}:
			var ok bool
			current, ok = v[part]
			if !ok {
				return nil, fmt.Errorf("路径 '%s' 中字段 '%s' 不存在", path, part)
			}

		case []interface{}:
			idx, err := strconv.Atoi(part)
			if err != nil {
				return nil, fmt.Errorf("路径 '%s' 中 '%s' 不是有效的数组索引", path, part)
			}
			if idx < 0 || idx >= len(v) {
				return nil, fmt.Errorf("路径 '%s' 中索引 %d 越界（数组长度 %d）", path, idx, len(v))
			}
			current = v[idx]

		default:
			return nil, fmt.Errorf("路径 '%s' 中无法继续导航：'%s' 不是对象或数组", path, part)
		}
	}

	return current, nil
}
