/**
 * Trip AI Tool Registry — server-executable tools for rTrips AI planner.
 * Unlike canvas-tools (display-only), these execute server-side and return real data.
 */

export interface TripToolDefinition {
	declaration: {
		name: string;
		description: string;
		parameters: {
			type: "object";
			properties: Record<string, { type: string; description: string; enum?: string[] }>;
			required: string[];
		};
	};
	execute: (args: Record<string, any>, env: { osrmUrl: string }) => Promise<any>;
	actionLabel: (args: Record<string, any>) => string;
}

const KIWI_API_KEY = process.env.KIWI_API_KEY || "";

const tripTools: TripToolDefinition[] = [
	{
		declaration: {
			name: "search_flights",
			description: "Search for flights between two cities. Returns real flight options with prices and booking links.",
			parameters: {
				type: "object",
				properties: {
					from: { type: "string", description: "Departure city or IATA code (e.g. 'Paris' or 'CDG')" },
					to: { type: "string", description: "Arrival city or IATA code (e.g. 'Tokyo' or 'NRT')" },
					departDate: { type: "string", description: "Departure date in YYYY-MM-DD format" },
					returnDate: { type: "string", description: "Return date in YYYY-MM-DD (optional for one-way)" },
					passengers: { type: "number", description: "Number of passengers (default 1)" },
					currency: { type: "string", description: "Currency code (default EUR)" },
				},
				required: ["from", "to", "departDate"],
			},
		},
		async execute(args) {
			const { from, to, departDate, returnDate, passengers = 1, currency = "EUR" } = args;
			const dateOut = departDate.replace(/-/g, "/");

			// Build Kiwi search URL (always works, no API key needed)
			const searchUrl = `https://www.kiwi.com/en/search/results/${encodeURIComponent(from)}/${encodeURIComponent(to)}/${dateOut}${returnDate ? "/" + returnDate.replace(/-/g, "/") : ""}/${passengers}adults`;

			if (!KIWI_API_KEY) {
				return {
					flights: [],
					searchUrl,
					note: "Flight search API not configured — use the link to search on Kiwi.com",
				};
			}

			try {
				const params = new URLSearchParams({
					fly_from: from,
					fly_to: to,
					date_from: departDate.replace(/-/g, "/"),
					date_to: departDate.replace(/-/g, "/"),
					curr: currency,
					adults: String(passengers),
					limit: "5",
					sort: "price",
					max_stopovers: "2",
				});
				if (returnDate) {
					params.set("return_from", returnDate.replace(/-/g, "/"));
					params.set("return_to", returnDate.replace(/-/g, "/"));
				}

				const res = await fetch(`https://api.tequila.kiwi.com/v2/search?${params}`, {
					headers: { apikey: KIWI_API_KEY },
				});
				if (!res.ok) throw new Error(`Kiwi API ${res.status}`);
				const data = await res.json();

				const flights = (data.data || []).slice(0, 5).map((f: any) => ({
					price: f.price,
					currency: f.currency || currency,
					airline: f.airlines?.join(", ") || "Unknown",
					duration: formatDuration(f.duration?.total || 0),
					stops: f.route ? Math.max(0, f.route.length - 1) : 0,
					departTime: f.dTime ? new Date(f.dTime * 1000).toISOString() : null,
					arriveTime: f.aTime ? new Date(f.aTime * 1000).toISOString() : null,
					bookingUrl: f.deep_link || searchUrl,
				}));

				return { flights, searchUrl };
			} catch (e: any) {
				return { flights: [], searchUrl, error: e.message };
			}
		},
		actionLabel: (args) => `Searching flights ${args.from} → ${args.to}`,
	},

	{
		declaration: {
			name: "get_route",
			description: "Get driving route between two points with distance and duration.",
			parameters: {
				type: "object",
				properties: {
					startLat: { type: "number", description: "Start latitude" },
					startLng: { type: "number", description: "Start longitude" },
					endLat: { type: "number", description: "End latitude" },
					endLng: { type: "number", description: "End longitude" },
					mode: { type: "string", description: "Routing mode: driving (default), walking, cycling", enum: ["driving", "walking", "cycling"] },
				},
				required: ["startLat", "startLng", "endLat", "endLng"],
			},
		},
		async execute(args, env) {
			const { startLat, startLng, endLat, endLng, mode = "driving" } = args;
			const profile = mode === "walking" ? "foot" : mode === "cycling" ? "bicycle" : "driving";
			const url = `${env.osrmUrl}/route/v1/${profile}/${startLng},${startLat};${endLng},${endLat}?geometries=geojson&overview=full`;

			try {
				const res = await fetch(url);
				if (!res.ok) throw new Error(`OSRM ${res.status}`);
				const data = await res.json();
				const route = data.routes?.[0];
				if (!route) return { error: "No route found" };

				return {
					distance: route.distance, // meters
					duration: route.duration, // seconds
					distanceKm: Math.round(route.distance / 100) / 10,
					durationFormatted: formatDuration(route.duration),
					geometry: route.geometry, // GeoJSON LineString
				};
			} catch (e: any) {
				return { error: e.message || "OSRM unavailable" };
			}
		},
		actionLabel: (args) => `Getting route (${args.mode || "driving"})`,
	},

	{
		declaration: {
			name: "geocode_place",
			description: "Look up the coordinates (latitude/longitude) of a city, address, or place name.",
			parameters: {
				type: "object",
				properties: {
					query: { type: "string", description: "Place name, city, or address to geocode" },
				},
				required: ["query"],
			},
		},
		async execute(args) {
			const { query } = args;
			try {
				const url = `https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURIComponent(query)}`;
				const res = await fetch(url, {
					headers: { "User-Agent": "rTrips/1.0 (rspace.online)" },
				});
				if (!res.ok) throw new Error(`Nominatim ${res.status}`);
				const data = await res.json();
				if (!data.length) return { error: "Place not found" };

				const place = data[0];
				return {
					lat: parseFloat(place.lat),
					lng: parseFloat(place.lon),
					displayName: place.display_name,
					type: place.type,
				};
			} catch (e: any) {
				return { error: e.message || "Geocoding failed" };
			}
		},
		actionLabel: (args) => `Looking up "${args.query}"`,
	},

	{
		declaration: {
			name: "find_nearby",
			description: "Find nearby points of interest (restaurants, hotels, attractions, etc.) around a location.",
			parameters: {
				type: "object",
				properties: {
					lat: { type: "number", description: "Latitude of the search center" },
					lng: { type: "number", description: "Longitude of the search center" },
					category: { type: "string", description: "POI category to search for", enum: ["restaurant", "hotel", "cafe", "museum", "temple", "park", "hospital", "supermarket", "attraction"] },
					radius: { type: "number", description: "Search radius in meters (default 1000)" },
				},
				required: ["lat", "lng", "category"],
			},
		},
		async execute(args) {
			const { lat, lng, category, radius = 1000 } = args;
			const tagMap: Record<string, string> = {
				restaurant: '["amenity"="restaurant"]',
				hotel: '["tourism"="hotel"]',
				cafe: '["amenity"="cafe"]',
				museum: '["tourism"="museum"]',
				temple: '["amenity"="place_of_worship"]',
				park: '["leisure"="park"]',
				hospital: '["amenity"="hospital"]',
				supermarket: '["shop"="supermarket"]',
				attraction: '["tourism"="attraction"]',
			};
			const tag = tagMap[category] || `["amenity"="${category}"]`;

			try {
				const query = `[out:json][timeout:10];(node${tag}(around:${radius},${lat},${lng});way${tag}(around:${radius},${lat},${lng}););out center 10;`;
				const res = await fetch("https://overpass-api.de/api/interpreter", {
					method: "POST",
					body: `data=${encodeURIComponent(query)}`,
					headers: { "Content-Type": "application/x-www-form-urlencoded" },
				});
				if (!res.ok) throw new Error(`Overpass ${res.status}`);
				const data = await res.json();

				const results = (data.elements || []).slice(0, 8).map((el: any) => {
					const elLat = el.lat || el.center?.lat;
					const elLng = el.lon || el.center?.lon;
					const dist = elLat && elLng ? haversineDistance(lat, lng, elLat, elLng) : null;
					return {
						name: el.tags?.name || "Unnamed",
						type: el.tags?.cuisine || el.tags?.tourism || el.tags?.amenity || category,
						lat: elLat,
						lng: elLng,
						distance: dist ? Math.round(dist) : null,
						tags: el.tags || {},
					};
				}).filter((r: any) => r.name !== "Unnamed")
					.sort((a: any, b: any) => (a.distance || 9999) - (b.distance || 9999));

				return { results, count: results.length, category, center: { lat, lng } };
			} catch (e: any) {
				return { results: [], error: e.message || "Overpass query failed" };
			}
		},
		actionLabel: (args) => `Finding ${args.category}s nearby`,
	},
];

function formatDuration(seconds: number): string {
	const h = Math.floor(seconds / 3600);
	const m = Math.round((seconds % 3600) / 60);
	if (h === 0) return `${m}m`;
	return `${h}h${m > 0 ? ` ${m}m` : ""}`;
}

function haversineDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
	const R = 6371000;
	const dLat = (lat2 - lat1) * Math.PI / 180;
	const dLon = (lon2 - lon1) * Math.PI / 180;
	const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) ** 2;
	return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}

export const TRIP_TOOLS: TripToolDefinition[] = [...tripTools];
export const TRIP_TOOL_DECLARATIONS = TRIP_TOOLS.map((t) => t.declaration);
export function findTripTool(name: string): TripToolDefinition | undefined {
	return TRIP_TOOLS.find((t) => t.declaration.name === name);
}
