package tools

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"

	htmltomarkdownnnn "github.com/JohannesKaufmann/html-to-markdown/v2"
	"github.com/athapong/aio-mcp/services"
	"github.com/athapong/aio-mcp/util"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"github.com/tidwall/gjson"
)

func RegisterWebSearchTool(s *server.MCPServer) {
	tool := mcp.NewTool("web_search",
		mcp.WithDescription("Search the web using Brave Search API"),
		mcp.WithString("query", mcp.Required(), mcp.Description("Query to search for (max 400 chars, 50 words)")),
		mcp.WithNumber("count", mcp.DefaultNumber(5), mcp.Description("Number of results (1-20, default 5)")),
		mcp.WithString("country", mcp.DefaultString("ALL"), mcp.Description("Country code")),
	)

	s.AddTool(tool, util.ErrorGuard(util.AdaptLegacyHandler(webSearchHandler)))
}

type SearchResult struct {
	Title       string `json:"title"`
	URL         string `json:"url"`
	Description string `json:"description"`
	Type        string `json:"type"`
	Age         string `json:"age"`
}

func webSearchHandler(arguments map[string]interface{}) (*mcp.CallToolResult, error) {
	query, ok := arguments["query"].(string)
	if !ok {
		return mcp.NewToolResultError("query must be a string"), nil
	}

	count := 10
	if countArg, ok := arguments["count"].(float64); ok {
		count = int(countArg)
		if count < 1 {
			count = 1
		} else if count > 20 {
			count = 20
		}
	}

	country := "ALL"
	if countryArg, ok := arguments["country"].(string); ok {
		country = countryArg
	}

	apiKey := os.Getenv("BRAVE_API_KEY")
	if apiKey == "" {
		return mcp.NewToolResultError("BRAVE_API_KEY environment variable is required"), nil
	}

	baseURL := "https://api.search.brave.com/res/v1/web/search"
	params := url.Values{}
	params.Add("q", query)
	params.Add("count", fmt.Sprintf("%d", count))
	params.Add("country", country)

	req, err := http.NewRequest("GET", baseURL+"?"+params.Encode(), nil)
	if err != nil {
		return mcp.NewToolResultError(fmt.Sprintf("Failed to create request: %v", err)), nil
	}

	req.Header.Set("Accept", "application/json")
	req.Header.Set("X-Subscription-Token", apiKey)

	resp, err := services.DefaultHttpClient().Do(req)
	if err != nil {
		return mcp.NewToolResultError(fmt.Sprintf("Failed to perform search: %v", err)), nil
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return mcp.NewToolResultError(fmt.Sprintf("Failed to read response: %v", err)), nil
	}

	if resp.StatusCode != http.StatusOK {
		return mcp.NewToolResultError(fmt.Sprintf("API request failed: %s", string(body))), nil
	}

	var results []*SearchResult

	gbody := gjson.ParseBytes(body)

	videoResults := gbody.Get("videos.results")
	for _, video := range videoResults.Array() {

		mdContent, err := htmltomarkdownnnn.ConvertString(video.Get("description").String())
		if err != nil {
			return nil, fmt.Errorf("failed to convert HTML to Markdown: %v", err)
		}

		results = append(results, &SearchResult{
			Title:       video.Get("title").String(),
			URL:         video.Get("url").String(),
			Description: mdContent,
			Type:        "video",
			Age:         video.Get("age").String(),
		})
	}

	webResults := gbody.Get("web.results")
	for _, web := range webResults.Array() {

		mdContent, err := htmltomarkdownnnn.ConvertString(web.Get("description").String())
		if err != nil {
			return nil, fmt.Errorf("failed to convert HTML to Markdown: %v", err)
		}

		results = append(results, &SearchResult{
			Title:       web.Get("title").String(),
			URL:         web.Get("url").String(),
			Description: mdContent,
			Type:        "web",
			Age:         web.Get("age").String(),
		})
	}

	if len(results) == 0 {
		return mcp.NewToolResultError("No results found, pls try again with a different query"), nil
	}

	responseText := ""
	for _, result := range results {
		responseText += fmt.Sprintf("Title: %s\nURL: %s\nDescription: %s\nType: %s\nAge: %s\n\n",
			result.Title, result.URL, result.Description, result.Type, result.Age)
	}

	return mcp.NewToolResultText(responseText), nil
}
