import { existsSync, mkdirSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { AgentTool } from "@jaeswift/jae-agent-core";
import { type Static, Type } from "@sinclair/typebox";

const browserSchema = Type.Object({
	action: Type.Union(
		[
			Type.Literal("navigate"),
			Type.Literal("screenshot"),
			Type.Literal("click"),
			Type.Literal("type"),
			Type.Literal("content"),
			Type.Literal("close"),
		],
		{
			description:
				"navigate: go to URL | screenshot: capture page | click: click element | type: type into element | content: get page text | close: close browser",
		},
	),
	url: Type.Optional(Type.String({ description: "URL to navigate to (for navigate action)" })),
	selector: Type.Optional(Type.String({ description: "CSS selector (for click/type actions)" })),
	text: Type.Optional(Type.String({ description: "Text to type (for type action)" })),
	wait: Type.Optional(Type.Number({ description: "Milliseconds to wait after action (default: 1000)" })),
});

export type BrowserToolInput = Static<typeof browserSchema>;

export interface BrowserToolDetails {
	action: string;
	url?: string;
	screenshotPath?: string;
	error?: string;
}

let _playwright: any = null;
let _browser: any = null;
let _page: any = null;

async function getPlaywright() {
	if (!_playwright) {
		try {
			const { chromium } = await import("playwright");
			_playwright = chromium;
		} catch {
			throw new Error("Playwright not installed. Run: npm install -g playwright && npx playwright install chromium");
		}
	}
	return _playwright;
}

async function getPage() {
	const pw = await getPlaywright();
	if (!_browser) _browser = await pw.launch({ headless: true });
	if (!_page) _page = await _browser.newPage();
	return _page;
}

export const browserTool: AgentTool<typeof browserSchema, BrowserToolDetails> = {
	name: "browser",
	label: "Browser",
	description:
		"Control a headless Chromium browser. Navigate pages, take screenshots, click elements, type text, and extract page content. Requires playwright.",
	parameters: browserSchema,
	async execute(toolCallId, params, signal) {
		const { action, url, selector, text, wait = 1000 } = params;

		try {
			if (action === "close") {
				if (_browser) {
					await _browser.close();
					_browser = null;
					_page = null;
				}
				return { content: [{ type: "text", text: "Browser closed." }], details: { action } };
			}

			const page = await getPage();

			if (action === "navigate") {
				if (!url)
					return { content: [{ type: "text", text: "Error: url required for navigate" }], details: { action } };
				await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
				await page.waitForTimeout(wait);
				const title = await page.title();
				return {
					content: [{ type: "text", text: `Navigated to: ${url}\nPage title: ${title}` }],
					details: { action, url },
				};
			}

			if (action === "screenshot") {
				const dir = join(tmpdir(), "jae-browser");
				if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
				const path = join(dir, `screenshot-${Date.now()}.png`);
				await page.screenshot({ path, fullPage: false });
				const currentUrl = page.url();
				return {
					content: [{ type: "text", text: `Screenshot saved to: ${path}\nCurrent URL: ${currentUrl}` }],
					details: { action, url: currentUrl, screenshotPath: path },
				};
			}

			if (action === "content") {
				const content = await page.evaluate(() => document.body.innerText);
				const truncated = content.slice(0, 8000);
				return {
					content: [{ type: "text", text: truncated + (content.length > 8000 ? "\n...[truncated]" : "") }],
					details: { action, url: page.url() },
				};
			}

			if (action === "click") {
				if (!selector)
					return { content: [{ type: "text", text: "Error: selector required for click" }], details: { action } };
				await page.click(selector, { timeout: 10000 });
				await page.waitForTimeout(wait);
				return { content: [{ type: "text", text: `Clicked: ${selector}` }], details: { action } };
			}

			if (action === "type") {
				if (!selector)
					return { content: [{ type: "text", text: "Error: selector required for type" }], details: { action } };
				if (!text)
					return { content: [{ type: "text", text: "Error: text required for type" }], details: { action } };
				await page.fill(selector, text);
				await page.waitForTimeout(wait);
				return { content: [{ type: "text", text: `Typed into: ${selector}` }], details: { action } };
			}

			return { content: [{ type: "text", text: `Unknown action: ${action}` }], details: { action } };
		} catch (err: any) {
			return {
				content: [{ type: "text", text: `Browser error: ${err.message}` }],
				details: { action, error: err.message },
			};
		}
	},
};
