import logger from '../logger';
import Anthropic from '@anthropic-ai/sdk';
import { AIConfig, CONFIG } from '../config';
import { MessageParam, TextBlock } from '@anthropic-ai/sdk/resources';
import Roboto from "../bot/roboto";
import NodeCache from "node-cache";
import { AIRole, AIService, ToolExecutionContext } from "../interfaces/ai-interfaces";
import { countMessages, sanitizeForLog, trimCachePreserveMessageStart } from "../utils";
import { ChatConfiguration } from "../config/chat-configurations";

class AnthropicService implements AIService<MessageParam, any> {

  private anthropic : Anthropic;
  private messagesCache = new NodeCache();

  constructor() {
    this.anthropic = new Anthropic({
      apiKey: AIConfig.ChatConfig.apiKey,
    });
  }

  public deleteChatCache(chatId: string){
    this.messagesCache.del(chatId);
  }

  public addMessageToCache(item: MessageParam, chatId: string){
    const aiMessages: any[] = this.messagesCache.get(chatId) || [];
    aiMessages.push(item);
    this.messagesCache.set(chatId, aiMessages, CONFIG.BotConfig.nodeCacheTime);
  }
  public hasChatCache(chatId: string): boolean {
    return this.messagesCache.has(chatId);
  }

  public async sendMessage(aiMessagesInputList: MessageParam[], systemPrompt: string, chatConfig: ChatConfiguration, tools: any, toolContext?: ToolExecutionContext): Promise<string> {
    let cycleCount = 0;
    const maxCycles = 5;
    const chatId = chatConfig.chatId;

    const aiMessages: any[]  = this.messagesCache.get(chatId) || [];
    aiMessages.push(...aiMessagesInputList)

    while (cycleCount < maxCycles) {
      const aiResponse: Anthropic.Messages.Message = await this.sendToApi(aiMessages, systemPrompt, tools);

      let hasFunctionCall = false;

      aiMessages.push({
        role: AIRole.ASSISTANT,
        content: aiResponse.content
      })

      const resultContent = [];

      for (const c of aiResponse.content) {

        if (c.type == 'tool_use') {
          hasFunctionCall = true;
          const functionResult = await Roboto.handleFunction(c.name, c.input, toolContext);

          resultContent.push({
            type: "tool_result",
            tool_use_id: c.id,
            content: JSON.stringify(functionResult)
          })
        }
      }

      if(resultContent.length>0)
        aiMessages.push({
          role: AIRole.USER,
          content: resultContent
        });

      cycleCount += 1;

      if (!hasFunctionCall) {
        const finalMsgList = trimCachePreserveMessageStart(aiMessages, chatConfig.maxMsgsLimit ?? 30);
        this.messagesCache.set(chatId, finalMsgList, CONFIG.BotConfig.nodeCacheTime);
        const content = aiResponse.content[0];
        if (!content || content.type !== 'text') {
          logger.warn(`[Anthropic->sendMessage] Unexpected response block type: ${content?.type ?? 'undefined'} for chat ${chatId}`);
          return "";
        }
        return (content as TextBlock)?.text || "";
      }
    }

    throw new Error(`Reached the limit of ${maxCycles} communication cycles with Claude.`);
  }

  async sendToApi(
      messageList: MessageParam[],
      systemPrompt: string,
      tools: any
  ) {

    logger.debug(`[Claude->sendCompletion] Sending ${countMessages(messageList)} messages.`);

    const response = await this.anthropic.messages.create({
      system: systemPrompt,
      model: AIConfig.ChatConfig.model,
      messages: messageList,
      max_tokens: CONFIG.BotConfig.claudeMaxTokens,
      top_p: 1,
      tools
    });

    logger.debug(`[Claude->sendCompletion] Completion Response: ${sanitizeForLog(response.content[0])?.type ?? 'unknown'} block`);

    return response;

    // const responseContent = response.content[0] as TextBlock;
    //
    // return responseContent;
  }

}



const AnthropicSvc = new AnthropicService();
export default AnthropicSvc
