/**
 * MCP tool exposing free-text geocoding and autocomplete.
 */

import BaseTool from "./BaseTool.js";
import { z } from "zod";

import { geocodeClient, GEOCODE_SOURCE } from "../gpf/geocode.js";
import { READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS } from "../helpers/toolAnnotations.js";
import logger from "../logger.js";

// --- Schema ---

const geocodeInputSchema = z.object({
  text: z
    .string()
    .trim()
    .min(1, "le texte ne doit pas être vide")
    .describe("Le texte devant être complété et géocodé"),
  maximumResponses: z
    .number()
    .int()
    .min(1)
    .max(10)
    .optional()
    .describe("Le nombre maximum de résultats à retourner (entre 1 et 10). Défaut : 3."),
}).strict();

// --- Types ---

type GeocodeInput = z.infer<typeof geocodeInputSchema>;

const geocodeResultSchema = z.object({
  lon: z.number().describe("La longitude du résultat."),
  lat: z.number().describe("La latitude du résultat."),
  fulltext: z.string().describe("Le libellé complet du résultat."),
  kind: z.string().describe("La nature du résultat géocodé.").optional(),
  city: z.string().describe("La commune du résultat.").optional(),
  zipcode: z.string().describe("Le code postal du résultat.").optional(),
});

const geocodeOutputSchema = z.object({
  results: z.array(geocodeResultSchema).describe("La liste ordonnée des résultats géocodés."),
});

// --- Tool ---

class GeocodeTool extends BaseTool<GeocodeInput> {
  name = "geocode";
  title = "Géocodage de lieux et d’adresses";
  annotations = READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS;
  description = [
    "Renvoie des résultats d'autocomplétion géocodés à partir d'un texte libre (lieu, adresse, POI), avec coordonnées, libellé complet et informations de localisation (`kind`, `city`, `zipcode`).",
    "Les coordonnées `lon/lat` retournées sont directement réutilisables dans tous les autres tools. Le champ `kind` indique le type de résultat (ex : `monument`, `street`, `city`, `locality`).",
    `(source : ${GEOCODE_SOURCE}).`
  ].join("\n");
  protected outputSchemaShape = geocodeOutputSchema;

  schema = geocodeInputSchema;

  /**
   * Geocodes a free-text query and returns the ordered candidate list.
   *
   * @param input Normalized tool input.
   * @returns The ordered list of geocoded candidates.
   */
  async execute(input: GeocodeInput) {
    logger.info(`[tool] execute ${this.name} ...`, {
      input: input
    });
  
    return {
      results: await geocodeClient.geocode(input.text, input.maximumResponses),
    };
  }
}

export default GeocodeTool;
