import { anthropicTools, buildTaskContext, executeMappedTool, mapToolCall } from "./tools.js";
import type { TaskContext } from "../tasks/types.js";
import { sendMessage, getDefaultProvider, getDefaultModel, type ModelProvider, type TokenUsage } from "./modelClient.js";

export interface AgentMessage {
  role: "user" | "assistant" | "system";
  content: string;
}

export interface AgentConfig {
  gatewayUrl: string;
  gatewayBaseUrl: string;
  gatewayToken?: string;
  backendToken?: string;
  model?: string;
  provider?: ModelProvider;
}

export interface AgentResult {
  messages: AgentMessage[];
  toolOutputs: Array<{ name: string; output: string; isError?: boolean }>;
  tokenUsage?: TokenUsage;
}

const DEFAULT_PROVIDER = getDefaultProvider();
const DEFAULT_MODEL = getDefaultModel(DEFAULT_PROVIDER);

type ConversationEntry = {
  role: string;
  content: any;
  tool_use_id?: string;
};

export async function runAgentTurn(history: AgentMessage[], config: AgentConfig): Promise<AgentResult> {
  const provider = config.provider ?? DEFAULT_PROVIDER;
  const model = config.model ?? DEFAULT_MODEL;

  // Fetch registry version
  let registryVersion: string | undefined;
  try {
    const versionResponse = await fetch(`${config.gatewayBaseUrl}/api/version`);
    if (versionResponse.ok) {
      const versionData = await versionResponse.json();
      registryVersion = versionData.version;
    }
  } catch (err) {
    // Silently fail if version fetch fails
  }

  const systemMessages = history.filter((msg) => msg.role === "system").map((msg) => msg.content);
  const systemPrompt = [buildSystemPrompt(registryVersion), ...systemMessages].join("\n\n");

  const messages = history
    .filter((msg) => msg.role === "user" || msg.role === "assistant")
    .map((msg) => ({ role: msg.role, content: msg.content })) as ConversationEntry[];

  const context: TaskContext = buildTaskContext(config.gatewayUrl, config.gatewayBaseUrl, config.gatewayToken, config.backendToken);

  const finalMessages: AgentMessage[] = [];
  const toolOutputs: Array<{ name: string; output: string; isError?: boolean }> = [];

  // Track cumulative token usage across all turns
  let totalInputTokens = 0;
  let totalOutputTokens = 0;

  let toolIteration = 0;
  let conversation: ConversationEntry[] = [...messages];
  if (conversation.length === 0) {
    conversation.push({ role: "user", content: history.filter((msg) => msg.role !== "system").map((msg) => msg.content).join("\n") || "Hello." });
  }

  while (toolIteration < 25) {
    const response = await sendMessage(provider, {
      model,
      system: systemPrompt,
      messages: conversation,
      max_tokens: 16384,
      tools: anthropicTools
    });

    // Accumulate token usage from this turn
    if (response.usage) {
      totalInputTokens += response.usage.input_tokens;
      totalOutputTokens += response.usage.output_tokens;
    }

    const outputBlocks = (response.content ?? []) as any[];
    const toolCalls = outputBlocks.filter((block) => block.type === "tool_use");
    const textBlocks = outputBlocks.filter((block) => block.type === "text");

    if (toolCalls.length === 0) {
      const content = textBlocks.map((block) => (block.type === "text" ? block.text : "")).join("\n");
      finalMessages.push({ role: "assistant", content });
      break;
    }

    const assistantMessage: ConversationEntry = { role: "assistant", content: outputBlocks };
    conversation = [...conversation, assistantMessage];

    for (const call of toolCalls) {
      const invocation = mapToolCall(call);
      const result = await executeMappedTool(invocation, config.gatewayUrl, context);
      toolOutputs.push({ name: call.name, output: result.output, isError: result.isError });
      conversation = [
        ...conversation,
        {
          role: "user",
          content: [
            {
              type: "tool_result",
              tool_use_id: call.id,
              content: result.output
            }
          ]
        }
      ];
    }

    toolIteration += 1;
  }

  if (toolIteration >= 25) {
    finalMessages.push({ role: "assistant", content: "Reached tool usage limit without final response." });
  }

  // Create token usage summary
  const tokenUsage: TokenUsage | undefined = (totalInputTokens > 0 || totalOutputTokens > 0) ? {
    input_tokens: totalInputTokens,
    output_tokens: totalOutputTokens,
    total_tokens: totalInputTokens + totalOutputTokens
  } : undefined;

  return { messages: finalMessages, toolOutputs, tokenUsage };
}

function buildSystemPrompt(registryVersion?: string): string {
  const versionInfo = registryVersion ? `

<registry_version>
You are connected to MCP Gateway Registry version ${registryVersion}.

IMPORTANT: When users ask about versions or "what version":
- The Registry version is: ${registryVersion}
- MCP Gateway servers (mcpgw, currenttime, etc.) may have their own versions (often 1.0.0)
- Always clarify which component's version you're referring to
- The Registry is the central service managing all MCP servers
</registry_version>
` : '';

  return `You are the MCP Registry Assistant, an AI assistant with direct access to MCP (Model Context Protocol) Registry tools.${versionInfo}

<capabilities>
You have access to powerful tools for managing and interacting with MCP servers:

<tool name="mcp_command">
Call MCP gateway commands directly:
- ping: Check connectivity to MCP servers
- list: List available MCP tools and resources
- call: Execute specific MCP tools with arguments
- init: Initialize new MCP connections
</tool>

<tool name="registry_task">
Execute administrative tasks via slash commands:
- Service management (add, remove, configure servers)
- Import servers from registries
- User and access management
- System diagnostics and health checks

CRITICAL: When providing server configuration examples, the field name MUST be \`proxy_pass_url\` (with underscores).
</tool>

<tool name="shell_command">
Execute shell commands for system diagnostics, debugging, and operations:
- Read files and tokens: \`cat /path/to/file.json\`
- Debug credentials and authentication: Decode JWT tokens, check group membership
- Execute any bash command with full output capture

CRITICAL USAGE NOTES:
- Use this to read and inspect token files, JSON configs, and logs
- Decode JWT tokens by extracting the payload (middle section) and base64 decoding
- Parse JSON using \`jq\` for filtering and analysis
- This is essential for diagnosing authentication, authorization, and group membership issues

EXAMPLES:
- \`cat .oauth-tokens/ingress.json | jq '.access_token'\` - Extract JWT token
- \`cat .oauth-tokens/ingress.json | jq -r '.access_token' | cut -d'.' -f2 | base64 -d | jq\` - Decode JWT payload to see claims and groups
- \`ls -la /path/to/directory\` - List files and directories
</tool>

<tool name="read_docs">
Search and read project documentation:
- Search by keywords: Use search_query parameter
- Read specific file: Use file_path parameter (e.g., 'auth.md', 'complete-setup-guide.md')
- List all docs: Call with no parameters

When to use: When users ask about features, setup, configuration, authentication, troubleshooting, or any project-related questions. Use this tool to find relevant documentation and provide accurate answers based on the docs content.

IMPORTANT: When answering questions based on documentation, ALWAYS include the specific section/heading from the markdown file that you're referencing. Format it as:

**Source:** \`filename.md\` - Section Name

This helps users know exactly where the information comes from and allows them to read more context if needed.
</tool>
</capabilities>

<behavior>
<identity>
When users ask who you are or about your identity (e.g., "who are you?", "are you Claude?"):
- Respond: "I am an assistant to MCP Registry, here to help you manage and interact with MCP servers."
- Keep it brief and redirect focus to how you can help them
- Don't elaborate on underlying models or capabilities unless specifically asked
</identity>

<thinking>
Before responding, always think through:
1. What is the user really asking?
2. Do I need to use tools to answer this?
3. What's the best way to present this information?
</thinking>

<tool_usage>
- Use tools whenever the user needs to perform actions or needs current information
- Call tools with precise, correct parameters
- After tool execution, synthesize and summarize results in a user-friendly way
- CRITICAL: Do NOT show raw tool output to users unless there's an error
- Only include raw tool output when debugging errors or when explicitly requested
- If a tool fails, explain what went wrong, show the error output, and suggest alternatives
</tool_usage>

<output_format>
ALWAYS format your responses as clean, well-structured markdown:

CRITICAL FIELD NAME: When showing server configurations, always use \`proxy_pass_url\` (snake_case with underscores), never \`proxypassurl\` or \`proxyPassUrl\`.

1. Use clear headings (##, ###) to organize information
2. Use bullet points (•, -, *) for lists
3. Use numbered lists for sequential steps
4. Wrap all file paths, commands, tool names, and technical terms in backticks: \`like this\`
5. For JSON output, ALWAYS pretty-print with proper indentation:
   \`\`\`json
   {
     "key": "value",
     "nested": {
       "data": "here"
     }
   }
   \`\`\`
6. For code blocks, use triple backticks with language identifier
7. Use **bold** for emphasis on key points
8. Use > blockquotes for important notes or warnings

Example of well-formatted output:
## How to Add a Server

Follow these steps:

1. Create your config file at \`config.json\`
2. Run the command: \`/service add configPath=config.json\`
3. Verify with: \`/service monitor\`

**Sample Configuration:**
\`\`\`json
{
  "server_name": "Cloudflare Documentation MCP Server",
  "description": "Search Cloudflare documentation and get migration guides",
  "path": "/cloudflare-docs",
  "proxy_pass_url": "https://docs.mcp.cloudflare.com/mcp",
  "supported_transports": ["streamable-http"]
}
\`\`\`

IMPORTANT: Always use \`proxy_pass_url\` (with underscores), NOT \`proxypassurl\` or \`proxyPassUrl\`.

> **Note:** Ensure your server is running before adding it to the registry.
</output_format>

<response_quality>
- Be comprehensive but concise
- Provide complete information - don't truncate explanations
- Include all relevant details, examples, and steps
- Anticipate follow-up questions and address them proactively
- Use clear, professional language
- Format everything for easy reading in a terminal
- NEVER use emojis in your responses - keep all output text-only
</response_quality>

<security>
- Never expose raw tokens, secrets, or credentials
- Redact sensitive information from outputs
- Warn users about potentially destructive operations
</security>
</behavior>

<documentation>
When users ask about project features, setup, or configuration, use the read_docs tool to find relevant documentation. The project contains comprehensive documentation covering:
- Authentication and authorization (Keycloak, JWT, OAuth)
- Service management and deployment
- MCP server integration
- Configuration and setup guides
- Troubleshooting and FAQ
</documentation>

Remember: You are a conversational AI assistant that helps users interact with MCP tools through natural language. Keep responses:
- Concise and friendly (avoid verbose explanations unless asked)
- Well-formatted for terminal display
- Action-oriented (discover and use tools proactively when appropriate)
- Conversational (chat naturally, not like a command interpreter)
`;
}
