package tools

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

// HTTPTool sends arbitrary HTTP requests, more flexible than web_fetch.
// Supports custom methods, headers, and body.
type HTTPTool struct {
	client *http.Client
}

// NewHTTPTool creates an HTTP request tool.
func NewHTTPTool() *HTTPTool {
	return &HTTPTool{
		client: &http.Client{
			Timeout: 10 * time.Second,
		},
	}
}

// Definition returns the tool definition for LLM function calling.
func (t *HTTPTool) Definition() ToolDefinition {
	return ToolDefinition{
		Name:        "http_request",
		Description: "发送任意HTTP请求。比web_fetch更灵活，支持自定义请求方法、请求头和请求体。返回状态码、响应头和响应体。",
		Parameters: map[string]interface{}{
			"type": "object",
			"properties": map[string]interface{}{
				"url": map[string]interface{}{
					"type":        "string",
					"description": "请求URL，必须是完整的 http:// 或 https:// 链接",
				},
				"method": map[string]interface{}{
					"type":        "string",
					"enum":        []string{"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"},
					"description": "HTTP方法，默认GET",
				},
				"headers": map[string]interface{}{
					"type":        "object",
					"description": "请求头，键值对格式，如 {\"Content-Type\": \"application/json\", \"Authorization\": \"Bearer token123\"}",
				},
				"body": map[string]interface{}{
					"type":        "string",
					"description": "请求体内容",
				},
				"timeout": map[string]interface{}{
					"type":        "number",
					"description": "超时秒数，默认10秒",
				},
			},
			"required": []string{"url"},
		},
	}
}

// Execute sends an HTTP request.
func (t *HTTPTool) Execute(ctx context.Context, arguments map[string]interface{}) (*ToolResult, error) {
	url, ok := arguments["url"].(string)
	if !ok || url == "" {
		return &ToolResult{
			ToolName: "http_request",
			Success:  false,
			Error:    "缺少 url 参数",
		}, nil
	}

	// Security: only allow HTTP/HTTPS
	if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
		return &ToolResult{
			ToolName: "http_request",
			Success:  false,
			Error:    "仅支持 http:// 或 https:// 链接",
		}, nil
	}

	method, _ := arguments["method"].(string)
	if method == "" {
		method = "GET"
	}
	method = strings.ToUpper(method)

	// Validate method
	validMethods := map[string]bool{
		"GET": true, "POST": true, "PUT": true, "DELETE": true,
		"PATCH": true, "HEAD": true, "OPTIONS": true,
	}
	if !validMethods[method] {
		return &ToolResult{
			ToolName: "http_request",
			Success:  false,
			Error:    fmt.Sprintf("不支持的HTTP方法: %s", method),
		}, nil
	}

	// Handle timeout
	timeoutSec := 10.0
	if timeoutVal, ok := arguments["timeout"].(float64); ok && timeoutVal > 0 {
		timeoutSec = timeoutVal
	}

	// Create a client with the specified timeout
	client := &http.Client{
		Timeout: time.Duration(timeoutSec * float64(time.Second)),
	}

	// Build body reader
	var bodyReader io.Reader
	bodyStr, _ := arguments["body"].(string)
	if bodyStr != "" {
		bodyReader = strings.NewReader(bodyStr)
	}

	req, err := http.NewRequestWithContext(ctx, method, url, bodyReader)
	if err != nil {
		return &ToolResult{
			ToolName: "http_request",
			Success:  false,
			Error:    fmt.Sprintf("创建请求失败: %v", err),
		}, nil
	}

	// Set default User-Agent
	req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; CyreneBot/1.0)")

	// Parse custom headers
	if headersRaw, ok := arguments["headers"].(map[string]interface{}); ok {
		for k, v := range headersRaw {
			val, ok := v.(string)
			if !ok {
				val = fmt.Sprintf("%v", v)
			}
			req.Header.Set(k, val)
		}
	}

	resp, err := client.Do(req)
	if err != nil {
		return &ToolResult{
			ToolName: "http_request",
			Success:  false,
			Error:    fmt.Sprintf("请求失败: %v", err),
		}, nil
	}
	defer resp.Body.Close()

	// Read response body (limited to 50KB)
	const maxBodySize = 50 * 1024
	bodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, int64(maxBodySize)))
	if err != nil {
		return &ToolResult{
			ToolName: "http_request",
			Success:  false,
			Error:    fmt.Sprintf("读取响应失败: %v", err),
		}, nil
	}

	// Build response headers string
	var headerLines []string
	for k, vals := range resp.Header {
		for _, v := range vals {
			headerLines = append(headerLines, fmt.Sprintf("%s: %s", k, v))
		}
	}
	headersStr := strings.Join(headerLines, "\n")

	bodyTruncated := ""
	if len(bodyBytes) > maxBodySize {
		bodyTruncated = fmt.Sprintf("\n... [响应体已截断，原大小约 %d bytes]", len(bodyBytes))
	}

	result := fmt.Sprintf(
		"请求: %s %s\n状态: %d %s\n响应头:\n%s\n\n响应体 (%d bytes):\n%s%s",
		method, url,
		resp.StatusCode, resp.Status,
		headersStr,
		len(bodyBytes), string(bodyBytes), bodyTruncated,
	)

	return &ToolResult{
		ToolName: "http_request",
		Success:  resp.StatusCode < 500,
		Data:     result,
	}, nil
}
