import axios from 'axios';
import { ChatMessage, ChatOptions, ProviderResponse } from '../../../types/chat';
import { StandardizedToolCall } from '../../../types/tool';
import { AnthropicConfig } from './config';
import { AnthropicChatRequestBody, AnthropicChatResponse, AnthropicMessageContent, AnthropicToolUseContent, Tool } from './types';
import { convertToolSchema, convertMessages } from './tools';

export async function chat(
  config: AnthropicConfig,
  messages: ChatMessage[],
  options: ChatOptions,
  tools?: Tool[]
): Promise<ProviderResponse> {
  const url = config.getApiUrl();
  
  const convertedMessages = convertMessages(messages);

  const requestBody: AnthropicChatRequestBody = {
    model: config.model,
    messages: convertedMessages.filter(msg => msg.role !== 'system'),
    max_tokens: options.maxTokens || 4000,
    temperature: options.temperature,
  };

  // Combine all system messages into a single system parameter
  const systemMessages = convertedMessages.filter(msg => msg.role === 'system');
  if (systemMessages.length > 0) {
    requestBody.system = systemMessages.map(msg => msg.content).join('\n\n');
  }

  if (tools && tools.length > 0) {
    const toolNames = tools.map(tool => tool.name).join(', ');
    requestBody.system = (requestBody.system || '') + `\n\nYou have access to the following tools: ${toolNames}. Use them when necessary.`;
    const convertedTools = tools.map(tool => convertToolSchema(tool.getSchema() as any));
    requestBody.tools = convertedTools;
  }

  try {
    const response = await axios.post<AnthropicChatResponse>(url, requestBody, {
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': config.apiKey,
        'anthropic-version': '2023-06-01',
      },
    });

    return await createProviderResponse(response.data, tools || []);
  } catch (error) {
    if (axios.isAxiosError(error) && error.response) {
      throw new Error(`Anthropic API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
    }
    throw error;
  }
}

async function createProviderResponse(data: AnthropicChatResponse, tools: Tool[]): Promise<ProviderResponse> {
  const response: ProviderResponse = {
    content: '',
    toolCalls: [],
    usage: { 
      promptTokens: data.usage?.input_tokens || 0, 
      completionTokens: data.usage?.output_tokens || 0, 
      totalTokens: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0)
    },
  };

  for (const item of data.content) {
    if (item.type === 'text') {
      response.content += item.text;
    } else if (item.type === 'tool_use') {
      const toolUse = item as AnthropicToolUseContent;
      const toolCall: StandardizedToolCall = {
        name: toolUse.name,
        arguments: toolUse.input,
      };
      response.toolCalls && response.toolCalls.push(toolCall);

      const tool = tools.find(t => t.name === toolUse.name);
      if (tool) {
        try {
          const result = await tool.execute(toolUse.input, {} as any);
          response.content += `\n\nTool ${toolUse.name} result: ${typeof result === 'string' ? result : JSON.stringify(result)}`;
        } catch (error) {
          response.content += `\n\nError executing tool ${toolUse.name}: ${error}`;
        }
      } else {
        response.content += `\n\nError: Tool not found: ${toolUse.name}`;
      }
    }
  }

  // Update usage tokens with the latest data from the response
  response.usage = {
    promptTokens: data.usage?.input_tokens || 0,
    completionTokens: data.usage?.output_tokens || 0,
    totalTokens: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0)
  };

  return response;
}