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

type OllamaResponse = {
  message?: {
    role: "assistant";
    content?: string;
    tool_calls?: Array<{
      function: {
        name: string;
        arguments: Record<string, unknown>;
      };
    }>;
  };
};

type CoreMessage =
  | { role: "system" | "user" | "assistant"; content: string }
  | {
      role: "assistant";
      content: string;
      tool_calls: Array<{
        type: "function";
        function: { name: string; arguments: Record<string, unknown> };
      }>;
    }
  | { role: "tool"; tool_name: string; content: string };

function hasToolCalls(
  message: CoreMessage | null
): message is Extract<CoreMessage, { tool_calls: unknown }> {
  return Boolean(message && "tool_calls" in message);
}

function getCoreBaseUrl() {
  const baseUrl = process.env.MINDBOARD_CORE_URL || process.env.MINDAVIO_CORE_URL;
  if (!baseUrl) {
    throw new Error("MINDBOARD_CORE_URL is not configured.");
  }

  return baseUrl;
}

function parseState(providerState?: string): CoreMessage[] {
  if (!providerState) return [];

  try {
    return JSON.parse(providerState) as CoreMessage[];
  } catch {
    return [];
  }
}

function buildMessages(params: ProviderGenerateParams) {
  const priorMessages = parseState(params.providerState);

  if (!params.toolResults?.length) {
    return [
      { role: "system" as const, content: params.systemPrompt },
      ...params.messages.map((message) => ({
        role: message.role,
        content: message.content,
      })),
    ];
  }

  const toolCalls = priorMessages.length > 0 ? priorMessages[priorMessages.length - 1] : null;
  const toolMessages: CoreMessage[] = params.toolResults.map((result, index) => ({
    role: "tool",
    tool_name: hasToolCalls(toolCalls) && toolCalls.tool_calls[index]
      ? toolCalls.tool_calls[index].function.name
      : "tool",
    content: JSON.stringify(result.output),
  }));

  return [...priorMessages, ...toolMessages];
}

export async function generateWithMindavioCore(
  params: ProviderGenerateParams
): Promise<ProviderGenerateResult> {
  const messages = buildMessages(params);

  const response = await fetch(`${getCoreBaseUrl()}/api/chat`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: params.model,
      messages,
      stream: false,
      tools: params.tools.map((tool) => ({
        type: "function",
        function: {
          name: tool.name,
          description: tool.description,
          parameters: tool.input_schema,
        },
      })),
      options: {
        temperature: 0.2,
      },
    }),
  });

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

  const data = (await response.json()) as OllamaResponse;
  const assistantContent = data.message?.content || "";
  const toolCalls: ToolCall[] = (data.message?.tool_calls || []).map((toolCall, index) => ({
    id: `core_tool_${Date.now()}_${index}`,
    name: toolCall.function.name,
    arguments: toolCall.function.arguments || {},
  }));

  const nextMessages: CoreMessage[] = [
    ...messages,
    toolCalls.length > 0
      ? {
          role: "assistant",
          content: assistantContent,
          tool_calls: toolCalls.map((toolCall) => ({
            type: "function",
            function: {
              name: toolCall.name,
              arguments: toolCall.arguments,
            },
          })),
        }
      : {
          role: "assistant",
          content: assistantContent,
        },
  ];

  return {
    text: assistantContent,
    toolCalls,
    providerState: JSON.stringify(nextMessages),
  };
}
