package tools

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

// WebSearchTool 网页搜索工具 - 基于 SearXNG (或 DuckDuckGo fallback)
type WebSearchTool struct {
	client     *http.Client
	timeout    time.Duration
	searxngURL string
}

// NewWebSearchTool 创建网页搜索工具
func NewWebSearchTool() *WebSearchTool {
	return &WebSearchTool{
		client: &http.Client{
			Timeout: 10 * time.Second,
		},
		timeout: 10 * time.Second,
	}
}

// NewWebSearchToolWithURL 使用 SearXNG 创建搜索工具
func NewWebSearchToolWithURL(searxngURL string) *WebSearchTool {
	return &WebSearchTool{
		client: &http.Client{
			Timeout: 10 * time.Second,
		},
		timeout:    10 * time.Second,
		searxngURL: strings.TrimRight(searxngURL, "/"),
	}
}

// Definition 返回工具定义
func (t *WebSearchTool) Definition() ToolDefinition {
	return ToolDefinition{
		Name:        "web_search",
		Description: "搜索互联网信息。用于查找新闻、资料、知识等。返回搜索结果摘要（最多5条）。",
		Parameters: map[string]interface{}{
			"type": "object",
			"properties": map[string]interface{}{
				"query": map[string]interface{}{
					"type":        "string",
					"description": "搜索关键词",
				},
			},
			"required": []string{"query"},
		},
	}
}

// duckDuckGoResponse DuckDuckGo API 响应
type duckDuckGoResponse struct {
	AbstractText string `json:"AbstractText"`
	AbstractURL  string `json:"AbstractURL"`
	AbstractSource string `json:"AbstractSource"`
	Heading      string `json:"Heading"`
	Answer       string `json:"Answer"`
	AnswerType   string `json:"AnswerType"`
	RelatedTopics []duckDuckGoRelated `json:"RelatedTopics"`
	Results      []duckDuckGoResult   `json:"Results"`
}

type duckDuckGoRelated struct {
	Text     string `json:"Text"`
	FirstURL string `json:"FirstURL"`
}

type duckDuckGoResult struct {
	Text     string `json:"Text"`
	FirstURL string `json:"FirstURL"`
}

// Execute 执行网页搜索
func (t *WebSearchTool) Execute(ctx context.Context, arguments map[string]interface{}) (*ToolResult, error) {
	query, ok := arguments["query"].(string)
	if !ok || query == "" {
		return &ToolResult{
			ToolName: "web_search",
			Success:  false,
			Error:    "缺少 query 参数",
		}, nil
	}

	if t.searxngURL != "" {
		return t.searchViaSearXNG(ctx, query)
	}
	return t.searchViaDuckDuckGo(ctx, query)
}

func (t *WebSearchTool) searchViaSearXNG(ctx context.Context, query string) (*ToolResult, error) {
	apiURL := fmt.Sprintf("%s/search?format=json&engines=bing,sogou,360search,baidu&q=%s",
		t.searxngURL, url.QueryEscape(query))

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

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

	if resp.StatusCode != http.StatusOK {
		return &ToolResult{ToolName: "web_search", Success: false, Error: fmt.Sprintf("SearXNG HTTP %d", resp.StatusCode)}, nil
	}

	var sr searxngAPIResponse
	if err := json.NewDecoder(resp.Body).Decode(&sr); err != nil {
		return &ToolResult{ToolName: "web_search", Success: false, Error: fmt.Sprintf("SearXNG 解析失败: %v", err)}, nil
	}

	var result strings.Builder
	result.WriteString(fmt.Sprintf("搜索关键词: %s (共%d条结果)\n\n", query, sr.NumberOrResults))

	for _, answer := range sr.Answers {
		result.WriteString(fmt.Sprintf("📌 %s\n\n", answer))
	}

	count := 0
	for _, r := range sr.Results {
		if count >= 5 {
			break
		}
		if r.Title == "" || r.URL == "" {
			continue
		}
		snippet := cleanSnippet(r.Content)
		result.WriteString(fmt.Sprintf("%d. %s\n   %s\n   %s\n\n", count+1, r.Title, r.URL, snippet))
		count++
	}

	if result.Len() == 0 {
		result.WriteString("未找到相关结果。")
	}

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

// searxngAPIResponse SearXNG JSON 响应
type searxngAPIResponse struct {
	NumberOrResults int              `json:"number_of_results"`
	Results         []searxngResult  `json:"results"`
	Answers         []string         `json:"answers"`
}

type searxngResult struct {
	Title   string  `json:"title"`
	URL     string  `json:"url"`
	Content string  `json:"content"`
	Score   float64 `json:"score"`
}

func cleanSnippet(s string) string {
	text := stripHTML(s)
	runes := []rune(text)
	if len(runes) > 200 {
		return string(runes[:200]) + "..."
	}
	return text
}

func (t *WebSearchTool) searchViaDuckDuckGo(ctx context.Context, query string) (*ToolResult, error) {
	apiURL := fmt.Sprintf("https://api.duckduckgo.com/?q=%s&format=json&no_html=1&skip_disambig=1",
		url.QueryEscape(query))

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

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

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

	if resp.StatusCode != http.StatusOK {
		return &ToolResult{ToolName: "web_search", Success: false, Error: fmt.Sprintf("HTTP %d", resp.StatusCode)}, nil
	}

	body, err := io.ReadAll(io.LimitReader(resp.Body, 500*1024))
	if err != nil {
		return &ToolResult{ToolName: "web_search", Success: false, Error: fmt.Sprintf("读取响应失败: %v", err)}, nil
	}

	var ddg duckDuckGoResponse
	if err := json.Unmarshal(body, &ddg); err != nil {
		return &ToolResult{ToolName: "web_search", Success: false, Error: fmt.Sprintf("解析响应失败: %v", err)}, nil
	}

	var result strings.Builder
	result.WriteString(fmt.Sprintf("搜索关键词: %s\n\n", query))

	if ddg.Answer != "" {
		result.WriteString(fmt.Sprintf("📌 即时答案: %s\n\n", ddg.Answer))
	}

	if ddg.AbstractText != "" {
		abstract := ddg.AbstractText
		if len([]rune(abstract)) > 500 {
			runes := []rune(abstract)
			abstract = string(runes[:500]) + "..."
		}
		result.WriteString(fmt.Sprintf("摘要: %s\n", abstract))
		if ddg.AbstractURL != "" {
			result.WriteString(fmt.Sprintf("来源: %s\n", ddg.AbstractURL))
		}
		result.WriteString("\n")
	}

	topics := ddg.RelatedTopics
	if len(ddg.Results) > 0 {
		count := 0
		for _, r := range ddg.Results {
			if count >= 5 {
				break
			}
			if r.Text != "" {
				text := stripHTML(r.Text)
				if len([]rune(text)) > 200 {
					runes := []rune(text)
					text = string(runes[:200]) + "..."
				}
				result.WriteString(fmt.Sprintf("\n🔗 %s\n", text))
				if r.FirstURL != "" {
					result.WriteString(fmt.Sprintf("   %s\n", r.FirstURL))
				}
				count++
			}
		}
	} else {
		count := 0
		for _, topic := range topics {
			if count >= 5 {
				break
			}
			if topic.Text != "" {
				text := stripHTML(topic.Text)
				if len([]rune(text)) > 200 {
					runes := []rune(text)
					text = string(runes[:200]) + "..."
				}
				result.WriteString(fmt.Sprintf("\n🔗 %s\n", text))
				if topic.FirstURL != "" {
					result.WriteString(fmt.Sprintf("   %s\n", topic.FirstURL))
				}
				count++
			}
		}
	}

	if result.Len() == 0 {
		result.WriteString("未找到相关结果。")
	}

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

// stripHTML 去除 HTML 标签
func stripHTML(s string) string {
	inTag := false
	var result []rune
	for _, r := range s {
		if r == '<' {
			inTag = true
			continue
		}
		if r == '>' {
			inTag = false
			// 替换常见块级标签为空格
			result = append(result, ' ')
			continue
		}
		if !inTag {
			result = append(result, r)
		}
	}
	return strings.TrimSpace(string(result))
}
