import type { AgentTool } from "@jaeswift/jae-agent-core";
import type { ToolResultMessage } from "@jaeswift/jae-ai";
import { Type } from "@sinclair/typebox";
import { html } from "lit";
import { Globe } from "lucide";
import { registerToolRenderer, renderHeader } from "./renderer-registry.js";
import type { ToolRenderer, ToolRenderResult } from "./types.js";

const webSearchSchema = Type.Object({
	query: Type.String({ description: "Search query" }),
	limit: Type.Optional(Type.Number({ description: "Max results (default: 5)" })),
});

export interface WebSearchResult {
	title: string;
	url: string;
	snippet: string;
}

export interface WebSearchDetails {
	results: WebSearchResult[];
	query: string;
	error?: string;
}

interface WebSearchParams {
	query: string;
	limit?: number;
}

async function fetchDuckDuckGo(query: string, limit: number): Promise<WebSearchResult[]> {
	const encoded = encodeURIComponent(query);
	const res = await fetch(
		`https://api.duckduckgo.com/?q=${encoded}&format=json&no_redirect=1&no_html=1&skip_disambig=1`,
	);
	if (!res.ok) throw new Error(`Search returned ${res.status}`);
	const data = (await res.json()) as any;
	const results: WebSearchResult[] = [];
	if (data.AbstractText && data.AbstractURL) {
		results.push({ title: data.Heading || query, url: data.AbstractURL, snippet: data.AbstractText });
	}
	for (const topic of data.RelatedTopics || []) {
		if (results.length >= limit) break;
		if (topic.FirstURL && topic.Text) {
			results.push({ title: topic.Text.split(" - ")[0], url: topic.FirstURL, snippet: topic.Text });
		} else if (topic.Topics) {
			for (const sub of topic.Topics) {
				if (results.length >= limit) break;
				if (sub.FirstURL && sub.Text)
					results.push({ title: sub.Text.split(" - ")[0], url: sub.FirstURL, snippet: sub.Text });
			}
		}
	}
	for (const r of data.Results || []) {
		if (results.length >= limit) break;
		if (r.FirstURL && r.Text) results.push({ title: r.Title || r.Text, url: r.FirstURL, snippet: r.Text });
	}
	return results.slice(0, limit);
}

export const webSearchTool: AgentTool<typeof webSearchSchema, WebSearchDetails> = {
	name: "web_search",
	label: "Web Search",
	description: "Search the web for current information using DuckDuckGo.",
	parameters: webSearchSchema,
	async execute(toolCallId, params, signal) {
		const { query, limit = 5 } = params;
		try {
			const results = await fetchDuckDuckGo(query, limit);
			const lines = results.map((r, i) => `[${i + 1}] ${r.title}` + "\n" + r.url + "\n" + r.snippet);
			const text = results.length === 0 ? `No results for: ${query}` : lines.join("\n\n");
			return { content: [{ type: "text", text }], details: { results, query } };
		} catch (err: any) {
			return {
				content: [{ type: "text", text: `Search failed: ${err.message}` }],
				details: { results: [], query, error: err.message },
			};
		}
	},
};

class WebSearchRenderer implements ToolRenderer<WebSearchParams, WebSearchDetails> {
	render(
		params: WebSearchParams | undefined,
		result: ToolResultMessage<WebSearchDetails> | undefined,
	): ToolRenderResult {
		const state = result ? (result.isError ? "error" : "complete") : "inprogress";
		if (result?.details?.results?.length) {
			const details = result.details;
			return {
				content: html`
          <div class="flex flex-col gap-3">
            ${renderHeader(state, Globe, `Web Search: ${details.query}`)}
            <div class="flex flex-col gap-2">
              ${details.results.map(
						(r) => html`
                <div class="flex flex-col gap-0.5 p-2 rounded border border-border bg-background">
                  <a href=${r.url} target="_blank" rel="noopener" class="text-sm font-medium text-primary hover:underline">${r.title}</a>
                  <span class="text-xs text-muted-foreground truncate">${r.url}</span>
                  <span class="text-xs text-foreground mt-1">${r.snippet}</span>
                </div>
              `,
					)}
            </div>
          </div>`,
				isCustom: false,
			};
		}
		return { content: renderHeader(state, Globe, `Searching: ${params?.query ?? "..."}`), isCustom: false };
	}
}

registerToolRenderer("web_search", new WebSearchRenderer());

export function createWebSearchTool(): AgentTool<typeof webSearchSchema, WebSearchDetails> {
	return webSearchTool;
}
