// retoor <retoor@molodetz.nl>
function requireAgent(app) {
  if (!app.agent) throw new Error("No character is currently loaded");
  return app.agent;
}

function number(value, fallback) {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
}

export function createClippyTools() {
  return [
    {
      name: "speak",
      description: "Show a line of text in devii's speech balloon.",
      parameters: {
        type: "object",
        properties: {
          text: { type: "string", description: "The text to display." },
          hold: {
            type: "boolean",
            description: "Keep the balloon open until the next action instead of auto-closing.",
          },
        },
        required: ["text"],
      },
      handler: (args, app) => {
        requireAgent(app).speak(String(args.text), { hold: !!args.hold });
        return "Displayed: " + args.text;
      },
    },
    {
      name: "list_animations",
      description: "List every animation the current character supports.",
      parameters: { type: "object", properties: {} },
      handler: (_args, app) => requireAgent(app).animations(),
    },
    {
      name: "play_animation",
      description: "Play a specific named animation. Call list_animations first if unsure.",
      parameters: {
        type: "object",
        properties: { name: { type: "string", description: "Exact animation name." } },
        required: ["name"],
      },
      handler: (args, app) => {
        const agent = requireAgent(app);
        if (!agent.hasAnimation(args.name)) {
          return "Error: no animation named '" + args.name + "'. Use list_animations.";
        }
        agent.play(args.name);
        return "Playing animation " + args.name;
      },
    },
    {
      name: "random_animation",
      description: "Play a random non-idle animation to react expressively.",
      parameters: { type: "object", properties: {} },
      handler: (_args, app) => {
        requireAgent(app).animate();
        return "Playing a random animation";
      },
    },
    {
      name: "move_to",
      description: "Walk the character to a pixel position on screen.",
      parameters: {
        type: "object",
        properties: {
          x: { type: "number" },
          y: { type: "number" },
          duration: { type: "number", description: "Movement duration in milliseconds." },
        },
        required: ["x", "y"],
      },
      handler: (args, app) => {
        const agent = requireAgent(app);
        const x = number(args.x);
        const y = number(args.y);
        if (x === undefined || y === undefined) return "Error: x and y must be numbers";
        agent.moveTo(x, y, number(args.duration, undefined));
        return "Moving to " + x + "," + y;
      },
    },
    {
      name: "gesture_at",
      description: "Make the character gesture toward a pixel position on screen.",
      parameters: {
        type: "object",
        properties: { x: { type: "number" }, y: { type: "number" } },
        required: ["x", "y"],
      },
      handler: (args, app) => {
        const agent = requireAgent(app);
        const x = number(args.x);
        const y = number(args.y);
        if (x === undefined || y === undefined) return "Error: x and y must be numbers";
        agent.gestureAt(x, y);
        return "Gesturing at " + x + "," + y;
      },
    },
    {
      name: "get_viewport",
      description: "Get the screen size and the character's current position.",
      parameters: { type: "object", properties: {} },
      handler: (_args, app) => {
        const agent = app.agent;
        const rect = agent ? agent._el.getBoundingClientRect() : null;
        return {
          width: window.innerWidth,
          height: window.innerHeight,
          character: app.name,
          position: rect ? { x: Math.round(rect.left), y: Math.round(rect.top) } : null,
        };
      },
    },
    {
      name: "show",
      description: "Show the character on screen.",
      parameters: { type: "object", properties: {} },
      handler: async (_args, app) => {
        await app.show();
        return "Character is visible";
      },
    },
    {
      name: "hide",
      description: "Hide the character.",
      parameters: { type: "object", properties: {} },
      handler: (_args, app) => {
        app.hide();
        return "Character is hidden";
      },
    },
    {
      name: "stop",
      description: "Stop all queued animations and speech immediately.",
      parameters: { type: "object", properties: {} },
      handler: (_args, app) => {
        app.stop();
        return "Stopped";
      },
    },
    {
      name: "list_characters",
      description: "List every character devii can appear as.",
      parameters: { type: "object", properties: {} },
      handler: (_args, app) => app.names(),
    },
    {
      name: "switch_character",
      description: "Change which character devii is rendered as.",
      parameters: {
        type: "object",
        properties: { name: { type: "string", description: "Character name." } },
        required: ["name"],
      },
      handler: async (args, app) => {
        await app.load(args.name);
        app.agent.show();
        return "Now appearing as " + args.name;
      },
    },
  ];
}
