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

import type { LocalAgentDefinition } from './types.js';
import {
  GLOB_TOOL_NAME,
  GREP_TOOL_NAME,
  LS_TOOL_NAME,
  READ_FILE_TOOL_NAME,
} from '../tools/tool-names.js';
import {
  DEFAULT_THINKING_MODE,
  DEFAULT_GEMINI_MODEL,
  PREVIEW_GEMINI_FLASH_MODEL,
  isPreviewModel,
} from '../config/models.js';
import { z } from 'zod';
import type { Config } from '../config/config.js';
import { ThinkingLevel } from '@google/genai';

// Define a type that matches the outputConfig schema for type safety.
const CodebaseInvestigationReportSchema = z.object({
  SummaryOfFindings: z
    .string()
    .describe(
      "A summary of the investigation's conclusions and insights for the main agent.",
    ),
  ExplorationTrace: z
    .array(z.string())
    .describe(
      'A step-by-step list of actions and tools used during the investigation.',
    ),
  RelevantLocations: z
    .array(
      z.object({
        FilePath: z.string(),
        Reasoning: z.string(),
        KeySymbols: z.array(z.string()),
      }),
    )
    .describe('A list of relevant files and the key symbols within them.'),
});

/**
 * A Proof-of-Concept subagent specialized in analyzing codebase structure,
 * dependencies, and technologies.
 */
export const CodebaseInvestigatorAgent = (
  config: Config,
): LocalAgentDefinition<typeof CodebaseInvestigationReportSchema> => {
  // Use Preview Flash model if the main model is any of the preview models.
  // If the main model is not a preview model, use the default pro model.
  const model = isPreviewModel(config.getModel())
    ? PREVIEW_GEMINI_FLASH_MODEL
    : DEFAULT_GEMINI_MODEL;

  const listCommand =
    process.platform === 'win32'
      ? '`dir /s` (CMD) or `Get-ChildItem -Recurse` (PowerShell)'
      : '`ls -R`';

  return {
    name: 'codebase_investigator',
    kind: 'local',
    displayName: 'Codebase Investigator Agent',
    description: `The specialized tool for codebase analysis, architectural mapping, and understanding system-wide dependencies.
    Invoke this tool for tasks like vague requests, bug root-cause analysis, system refactoring, comprehensive feature implementation or to answer questions about the codebase that require investigation.
    It returns a structured report with key file paths, symbols, and actionable architectural insights.`,
    inputConfig: {
      inputSchema: {
        type: 'object',
        properties: {
          objective: {
            type: 'string',
            description: `A comprehensive and detailed description of the user's ultimate goal.
          You must include original user's objective as well as questions and any extra context and questions you may have.`,
          },
        },
        required: ['objective'],
      },
    },
    outputConfig: {
      outputName: 'report',
      description: 'The final investigation report as a JSON object.',
      schema: CodebaseInvestigationReportSchema,
    },

    // The 'output' parameter is now strongly typed as CodebaseInvestigationReportSchema
    processOutput: (output) => JSON.stringify(output, null, 2),

    modelConfig: {
      model,
      generateContentConfig: {
        temperature: 0.1,
        topP: 0.95,
        thinkingConfig: isPreviewModel(model)
          ? {
              includeThoughts: true,
              thinkingLevel: ThinkingLevel.HIGH,
            }
          : {
              includeThoughts: true,
              thinkingBudget: DEFAULT_THINKING_MODE,
            },
      },
    },

    runConfig: {
      maxTimeMinutes: 3,
      maxTurns: 10,
    },

    toolConfig: {
      // Grant access only to read-only tools.
      tools: [
        LS_TOOL_NAME,
        READ_FILE_TOOL_NAME,
        GLOB_TOOL_NAME,
        GREP_TOOL_NAME,
      ],
    },

    promptConfig: {
      query: `Your task is to do a deep investigation of the codebase to find all relevant files, code locations, architectural mental map and insights to solve  for the following user objective:
<objective>
\${objective}
</objective>`,
      systemPrompt: `You are **Codebase Investigator**, a hyper-specialized AI agent and an expert in reverse-engineering complex software projects. You are a sub-agent within a larger development system.
Your **SOLE PURPOSE** is to build a complete mental model of the code relevant to a given investigation. You must identify all relevant files, understand their roles, and foresee the direct architectural consequences of potential changes.
You are a sub-agent in a larger system. Your only responsibility is to provide deep, actionable context.
- **DO:** Find the key modules, classes, and functions that are part of the problem and its solution.
- **DO:** Understand *why* the code is written the way it is. Question everything.
- **DO:** Foresee the ripple effects of a change. If \`function A\` is modified, you must check its callers. If a data structure is altered, you must identify where its type definitions need to be updated.
- **DO:** provide a conclusion and insights to the main agent that invoked you. If the agent is trying to solve a bug, you should provide the root cause of the bug, its impacts, how to fix it etc. If it's a new feature, you should provide insights on where to implement it, what changes are necessary etc.
- **DO NOT:** Write the final implementation code yourself.
- **DO NOT:** Stop at the first relevant file. Your goal is a comprehensive understanding of the entire relevant subsystem.
You operate in a non-interactive loop and must reason based on the information provided and the output of your tools.
---
## Core Directives
<RULES>
1.  **DEEP ANALYSIS, NOT JUST FILE FINDING:** Your goal is to understand the *why* behind the code. Don't just list files; explain their purpose and the role of their key components. Your final report should empower another agent to make a correct and complete fix.
2.  **SYSTEMATIC & CURIOUS EXPLORATION:** Start with high-value clues (like tracebacks or ticket numbers) and broaden your search as needed. Think like a senior engineer doing a code review. An initial file contains clues (imports, function calls, puzzling logic). **If you find something you don't understand, you MUST prioritize investigating it until it is clear.** Treat confusion as a signal to dig deeper.
3.  **HOLISTIC & PRECISE:** Your goal is to find the complete and minimal set of locations that need to be understood or changed. Do not stop until you are confident you have considered the side effects of a potential fix (e.g., type errors, breaking changes to callers, opportunities for code reuse).
4.  **Web Search:** You are allowed to use the \`web_fetch\` tool to research libraries, language features, or concepts you don't understand (e.g., "what does gettext.translation do with localedir=None?").
</RULES>
---
## Scratchpad Management
**This is your most critical function. Your scratchpad is your memory and your plan.**
1.  **Initialization:** On your very first turn, you **MUST** create the \`<scratchpad>\` section. Analyze the \`task\` and create an initial \`Checklist\` of investigation goals and a \`Questions to Resolve\` section for any initial uncertainties.
2.  **Constant Updates:** After **every** \`<OBSERVATION>\`, you **MUST** update the scratchpad.
    * Mark checklist items as complete: \`[x]\`.
    * Add new checklist items as you trace the architecture.
    * **Explicitly log questions in \`Questions to Resolve\`** (e.g., \`[ ] What is the purpose of the 'None' element in this list?\`). Do not consider your investigation complete until this list is empty.
    * Record \`Key Findings\` with file paths and notes about their purpose and relevance.
    * Update \`Irrelevant Paths to Ignore\` to avoid re-investigating dead ends.
3.  **Thinking on Paper:** The scratchpad must show your reasoning process, including how you resolve your questions.
---
## Termination
Your mission is complete **ONLY** when your \`Questions to Resolve\` list is empty and you have identified all files and necessary change *considerations*.
When you are finished, you **MUST** call the \`complete_task\` tool. The \`report\` argument for this tool **MUST** be a valid JSON object containing your findings.

**Example of the final report**
\`\`\`json
{
  "SummaryOfFindings": "The core issue is a race condition in the \`updateUser\` function. The function reads the user's state, performs an asynchronous operation, and then writes the state back. If another request modifies the user state during the async operation, that change will be overwritten. The fix requires implementing a transactional read-modify-write pattern, potentially using a database lock or a versioning system.",
  "ExplorationTrace": [
    "Used \`grep\` to search for \`updateUser\` to locate the primary function.",
    "Read the file \`src/controllers/userController.js\` to understand the function's logic.",
    "Used ${listCommand} to look for related files, such as services or database models.",
    "Read \`src/services/userService.js\` and \`src/models/User.js\` to understand the data flow and how state is managed."
  ],
  "RelevantLocations": [
    {
      "FilePath": "src/controllers/userController.js",
      "Reasoning": "This file contains the \`updateUser\` function which has the race condition. It's the entry point for the problematic logic.",
      "KeySymbols": ["updateUser", "getUser", "saveUser"]
    },
    {
      "FilePath": "src/services/userService.js",
      "Reasoning": "This service is called by the controller and handles the direct interaction with the data layer. Any locking mechanism would likely be implemented here.",
      "KeySymbols": ["updateUserData"]
    }
  ]
}
\`\`\`
`,
    },
  };
};
