import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import {
	DEFAULT_MAX_BYTES,
	DEFAULT_MAX_LINES,
	formatSize,
	truncateHead,
} from "@mariozechner/pi-coding-agent";
import { Type } from "@sinclair/typebox";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";

async function writeTempFile(content: string): Promise<string> {
	const dir = await fs.mkdtemp(path.join(os.tmpdir(), "pi-fetch-"));
	const filePath = path.join(dir, "response.txt");
	await fs.writeFile(filePath, content, "utf8");
	return filePath;
}

export default function (pi: ExtensionAPI) {
	pi.registerTool({
		name: "fetch_url",
		label: "Fetch URL",
		description:
			"Fetch a URL over HTTP(S) and return the response body as text (truncated to 50KB/2000 lines).",
		parameters: Type.Object({
			url: Type.String({ description: "URL to fetch" }),
			timeoutMs: Type.Optional(
				Type.Number({ description: "Timeout in milliseconds (default: 10000)" })
			),
			headers: Type.Optional(
				Type.Record(Type.String(), Type.String(), {
					description: "Optional request headers",
				})
			),
		}),
		async execute(_toolCallId, params, signal) {
			const controller = new AbortController();
			const timeout = setTimeout(
				() => controller.abort(),
				params.timeoutMs ?? 10000
			);

			const combinedSignal = signal
				? AbortSignal.any([signal, controller.signal])
				: controller.signal;

			try {
				const response = await fetch(params.url, {
					headers: params.headers,
					signal: combinedSignal,
				});
				const body = await response.text();
				const truncation = truncateHead(body, {
					maxLines: DEFAULT_MAX_LINES,
					maxBytes: DEFAULT_MAX_BYTES,
				});

				let content = truncation.content;
				if (truncation.truncated) {
					const tempFile = await writeTempFile(body);
					content += `\n\n[Output truncated: ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). Full output saved to: ${tempFile}]`;
				}

				return {
					content: [{ type: "text", text: content }],
					details: {
						status: response.status,
						statusText: response.statusText,
						contentType: response.headers.get("content-type"),
						url: response.url,
					},
				};
			} finally {
				clearTimeout(timeout);
			}
		},
	});
}
