import type {
  ProviderGenerateParams,
  ProviderGenerateResult,
  ToolCall,
} from "../types";

type AnthropicResponse = {
  id: string;
  content: Array<
    | { type: "text"; text: string }
    | { type: "tool_use"; id: string; name: string; input: Record<string, unknown> }
  >;
  stop_reason: string | null;
};

function toAnthropicMessages(params: ProviderGenerateParams) {
  if (!params.toolResults?.length) {
    return params.messages.map((message) => ({
      role: message.role,
      content: [{ type: "text", text: message.content }],
    }));
  }

  return [
    ...params.messages.map((message) => ({
      role: message.role,
      content: [{ type: "text", text: message.content }],
    })),
    {
      role: "user",
      content: params.toolResults.map((result) => ({
        type: "tool_result",
        tool_use_id: result.callId,
        content: JSON.stringify(result.output),
      })),
    },
  ];
}

export async function generateWithAnthropic(
  params: ProviderGenerateParams
): Promise<ProviderGenerateResult> {
  const response = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": params.apiKey,
      "anthropic-version": "2023-06-01",
    },
    body: JSON.stringify({
      model: params.model,
      system: params.systemPrompt,
      max_tokens: 1200,
      messages: toAnthropicMessages(params),
      tools: params.tools.map((tool) => ({
        name: tool.name,
        description: tool.description,
        input_schema: tool.input_schema,
      })),
    }),
  });

  if (!response.ok) {
    const text = await response.text();
    throw new Error(`Anthropic error: ${response.status} ${text}`);
  }

  const data = (await response.json()) as AnthropicResponse;
  const text = data.content
    .filter((item): item is { type: "text"; text: string } => item.type === "text")
    .map((item) => item.text)
    .join("\n")
    .trim();

  const toolCalls: ToolCall[] = data.content
    .filter(
      (item): item is { type: "tool_use"; id: string; name: string; input: Record<string, unknown> } =>
        item.type === "tool_use"
    )
    .map((item) => ({
      id: item.id,
      name: item.name,
      arguments: item.input,
    }));

  return {
    text,
    toolCalls,
    providerState: data.id,
  };
}
