import OpenAI from "openai";
import { ProposedEventChange } from "@calchat/shared";
import { AIProvider, AIContext, AIResponse } from "../services/interfaces";
import {
  buildSystemPrompt,
  TOOL_DEFINITIONS,
  executeToolCall,
  ToolDefinition,
} from "./utils";
import { Logged } from "../logging";
import {
  ChatCompletionMessageParam,
  ChatCompletionMessageToolCall,
  ChatCompletionTool,
} from "openai/resources/chat/completions/completions";

/**
 * Convert tool definitions to OpenAI format.
 */
function toOpenAITools(
  defs: ToolDefinition[],
): OpenAI.Chat.Completions.ChatCompletionTool[] {
  return defs.map((def) => ({
    type: "function" as const,
    function: {
      name: def.name,
      description: def.description,
      parameters: def.parameters,
    },
  }));
}

@Logged("GPTAdapter")
export class GPTAdapter implements AIProvider {
  private client: OpenAI;
  private model: string;
  private tools: ChatCompletionTool[];

  constructor(apiKey?: string, model: string = "gpt-5-mini") {
    this.client = new OpenAI({
      apiKey: apiKey || process.env.OPENAI_API_KEY,
    });
    this.model = model;
    this.tools = toOpenAITools(TOOL_DEFINITIONS);
  }

  async processMessage(
    message: string,
    context: AIContext,
  ): Promise<AIResponse> {
    const systemPrompt = buildSystemPrompt(context);

    // Build messages array with conversation history
    const messages: ChatCompletionMessageParam[] = [
      { role: "developer", content: systemPrompt },
    ];

    // Add conversation history
    for (const msg of context.conversationHistory) {
      messages.push({
        role: msg.sender === "user" ? "user" : "assistant",
        content: msg.content,
      });
    }

    // Add current user message
    messages.push({ role: "user", content: message });

    const proposedChanges: ProposedEventChange[] = [];
    let proposalIndex = 0;

    // Tool calling loop
    while (true) {
      const response = await this.client.chat.completions.create({
        model: this.model,
        messages,
        tools: this.tools,
      });

      const assistantMessage = response.choices[0].message;

      // If no tool calls, return the final response
      if (
        !assistantMessage.tool_calls ||
        assistantMessage.tool_calls.length === 0
      ) {
        return {
          content:
            assistantMessage.content || "Ich konnte keine Antwort generieren.",
          proposedChanges:
            proposedChanges.length > 0 ? proposedChanges : undefined,
        };
      }

      // Process all tool calls and collect results
      const toolResults: Array<{
        toolCall: ChatCompletionMessageToolCall;
        content: string;
      }> = [];

      for (const toolCall of assistantMessage.tool_calls) {
        if (toolCall.type !== "function") continue;

        const { name, arguments: argsRaw } = toolCall.function;
        const args = JSON.parse(argsRaw);

        const result = await executeToolCall(name, args, context);

        // Collect proposed changes
        if (result.proposedChange) {
          proposedChanges.push({
            id: `proposal-${proposalIndex++}`,
            ...result.proposedChange,
          });
        }

        toolResults.push({ toolCall, content: result.content });
      }

      // Add assistant message with ALL tool calls at once
      messages.push({
        role: "assistant",
        tool_calls: assistantMessage.tool_calls,
        content: assistantMessage.content,
      });

      // Add all tool results
      for (const { toolCall, content } of toolResults) {
        messages.push({
          role: "tool",
          tool_call_id: toolCall.id,
          content,
        });
      }
    }
  }
}
