/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { describe, expect } from 'vitest';
import { evalTest } from './test-helper.js';

describe('update_topic_behavior', () => {
  // Constants for tool names and params for robustness
  const UPDATE_TOPIC_TOOL_NAME = 'update_topic';

  /**
   * Verifies the desired behavior of the update_topic tool. update_topic is used by the
   * agent to share periodic, concise updates about what the agent is working on, independent
   * of the regular model output and/or thoughts. This tool is expected to be called at least
   * at the start and end of the session, and typically at least once in the middle, but no
   * more than 1/4 turns.
   */
  evalTest('USUALLY_PASSES', {
    name: 'update_topic should be used at start, end and middle for complex tasks',
    prompt: `Create a simple users REST API using Express. 
1. Initialize a new npm project and install express.
2. Create src/app.ts as the main entry point.
3. Create src/routes/userRoutes.ts for user routes.
4. Create src/controllers/userController.ts for user logic.
5. Implement GET /users, POST /users, and GET /users/:id using an in-memory array.
6. Add a 'start' script to package.json.
7. Finally, run a quick grep to verify the routes are in src/app.ts.`,
    files: {
      'package.json': JSON.stringify(
        {
          name: 'users-api',
          version: '1.0.0',
          private: true,
        },
        null,
        2,
      ),
      '.gemini/settings.json': JSON.stringify({
        experimental: {
          topicUpdateNarration: true,
        },
      }),
    },
    assert: async (rig, result) => {
      const toolLogs = rig.readToolLogs();
      const topicCalls = toolLogs.filter(
        (l) => l.toolRequest.name === UPDATE_TOPIC_TOOL_NAME,
      );

      // 1. Assert that update_topic is called at least 3 times (start, middle, end)
      expect(
        topicCalls.length,
        `Expected at least 3 update_topic calls, but found ${topicCalls.length}`,
      ).toBeGreaterThanOrEqual(3);

      // 2. Assert update_topic is called at the very beginning (first tool call)
      expect(
        toolLogs[0].toolRequest.name,
        'First tool call should be update_topic',
      ).toBe(UPDATE_TOPIC_TOOL_NAME);

      // 3. Assert update_topic is called near the end
      const lastTopicCallIndex = toolLogs
        .map((l) => l.toolRequest.name)
        .lastIndexOf(UPDATE_TOPIC_TOOL_NAME);
      expect(
        lastTopicCallIndex,
        'Expected update_topic to be used near the end of the task',
      ).toBeGreaterThanOrEqual(toolLogs.length * 0.7);

      // 4. Assert there is at least one update_topic call in the middle (between start and end phases)
      const middleTopicCalls = topicCalls.slice(1, -1);

      expect(
        middleTopicCalls.length,
        'Expected at least one update_topic call in the middle of the task',
      ).toBeGreaterThanOrEqual(1);

      // 5. Turn Ratio Assertion: update_topic should be <= 1/2 of total turns.
      // We only enforce this for tasks that take more than 5 turns, as shorter tasks
      // naturally have a higher ratio when following the "start, middle, end" rule.
      const uniquePromptIds = new Set(
        toolLogs
          .map((l) => l.toolRequest.prompt_id)
          .filter((id) => id !== undefined),
      );
      const totalTurns = uniquePromptIds.size;

      if (totalTurns > 5) {
        const topicTurns = new Set(
          topicCalls
            .map((l) => l.toolRequest.prompt_id)
            .filter((id) => id !== undefined),
        );
        const topicTurnCount = topicTurns.size;

        const ratio = topicTurnCount / totalTurns;

        expect(
          ratio,
          `update_topic was used in ${topicTurnCount} out of ${totalTurns} turns (${(ratio * 100).toFixed(1)}%). Expected <= 50%.`,
        ).toBeLessThanOrEqual(0.5);

        // Ideal ratio is closer to 1/5 (20%). We log high usage as a warning.
        if (ratio > 0.25) {
          console.warn(
            `[Efficiency Warning] update_topic usage is high: ${(ratio * 100).toFixed(1)}% (Goal: ~20%)`,
          );
        }
      }
    },
  });
});
