import { streamChat } from './api-client.js';
import { TOOL_DEFINITIONS, executeTool } from './tools.js';
import { getProviderById } from './providers.js';
import { getApiKeys, getSettings, saveConversation, generateId } from './utils.js';

const MAX_TOOL_ITERATIONS = 10;

function stripThinkingTags(text) {
  return text
    .replace(/<thought>[\s\S]*?<\/thought>/gi, '')
    .replace(/<think[^>]*>[\s\S]*?<\/think>/gi, '');
}

function buildToolMessages(messages, toolCall, result) {
  const toolCalls = Array.isArray(toolCall.toolCalls) ? toolCall.toolCalls : [{ id: toolCall.id, type: 'function', function: { name: toolCall.name, arguments: JSON.stringify(toolCall.arguments) } }];
  const firstId = toolCalls[0]?.id || `tc_${Date.now()}_0`;
  const assistantMsg = {
    role: 'assistant',
    content: toolCall.content || null,
    tool_calls: toolCalls.map((tc, i) => ({
      id: tc.id || `tc_${Date.now()}_${i}`,
      type: tc.type || 'function',
      function: tc.function || { name: toolCall.name, arguments: JSON.stringify(toolCall.arguments) }
    }))
  };
  const toolResultMsg = {
    role: 'tool',
    tool_call_id: firstId,
    content: typeof result === 'string' ? result : JSON.stringify(result)
  };
  return [...messages, assistantMsg, toolResultMsg];
}

function parseToolCallArguments(toolCall) {
  if (toolCall.arguments && typeof toolCall.arguments === 'string') {
    try { return JSON.parse(toolCall.arguments); } catch { return {}; }
  }
  if (toolCall.function?.arguments) {
    try { return JSON.parse(toolCall.function.arguments); } catch { return {}; }
  }
  return toolCall.arguments || {};
}

async function runChat(providerId, model, messages, onChunk, onToolCall, sender, passedSettings) {
  const apiKeys = await getApiKeys();
  const settings = passedSettings || await getSettings();
  const apiKey = apiKeys[providerId];
  const provider = getProviderById(providerId);

  if (!apiKey) {
    onChunk({ type: 'error', content: `Kein API Key fuer ${provider?.name || providerId}. Bitte in Settings eintragen.` });
    return { role: 'assistant', content: 'Fehler: Kein API Key konfiguriert.' };
  }

  const toolDefs = TOOL_DEFINITIONS;
  let currentMessages = [...messages];
  let fullResponse = '';
  let iteration = 0;
  let collectedToolCalls = [];
  let currentContent = '';

  while (iteration < MAX_TOOL_ITERATIONS) {
    currentContent = '';
    collectedToolCalls = [];
    let finishReason = null;

    const visionMessages = [...currentMessages];
    for (const msg of visionMessages) {
      if (msg.role === 'tool' && typeof msg.content === 'string') {
        let parsed;
        try { parsed = JSON.parse(msg.content); } catch { continue; }
        if (parsed?.screenshot && provider?.visionModels?.includes(model)) {
          const base64 = parsed.screenshot.replace(/^data:image\/\w+;base64,/, '');
          if (provider.format === 'openai') {
            msg.content = [
              { type: 'image_url', image_url: { url: `data:image/png;base64,${base64}` } },
              { type: 'text', text: 'Was siehst du auf diesem Screenshot? Beschreibe den Inhalt detailliert.' }
            ];
          } else if (provider.format === 'anthropic') {
            msg.content = [
              { type: 'image', source: { type: 'base64', media_type: 'image/png', data: base64 } },
              { type: 'text', text: 'Was siehst du auf diesem Screenshot? Beschreibe den Inhalt detailliert.' }
            ];
          } else if (provider.format === 'google') {
            msg.content = [{ text: `[Bild: base64 encoded Screenshot]` }];
          }
          msg.role = 'user';
        }
      }
    }

    try {
      const stream = streamChat(providerId, apiKey, model, visionMessages, toolDefs, settings);

      for await (const chunk of stream) {
        if (chunk.done) {
          break;
        }
        if (chunk.content) {
          const filtered = stripThinkingTags(chunk.content);
          if (filtered) {
            currentContent += filtered;
            onChunk({ type: 'content', content: filtered });
          }
        }
        if (chunk.toolCalls && chunk.toolCalls.length > 0) {
          for (const tc of chunk.toolCalls) {
            const existing = collectedToolCalls.find(c => c.id && tc.id && c.id === tc.id)
              || collectedToolCalls[tc.index];
            if (existing) {
              if (tc.function?.name) existing.function.name = tc.function.name;
              if (tc.function?.arguments) {
                existing.function.arguments = (existing.function.arguments || '') + tc.function.arguments;
              }
              if (tc.id && !existing.id) existing.id = tc.id;
            } else {
              collectedToolCalls[tc.index ?? collectedToolCalls.length] = {
                id: tc.id || null,
                type: tc.type || 'function',
                function: {
                  name: tc.function?.name || '',
                  arguments: tc.function?.arguments || ''
                }
              };
            }
          }
        }
        if (chunk.finishReason) {
          finishReason = chunk.finishReason;
        }
      }
    } catch (e) {
      onChunk({ type: 'error', content: `API Fehler: ${e.message}` });
      fullResponse += currentContent;
      break;
    }

    fullResponse += currentContent;

    if (collectedToolCalls.length === 0) {
      break;
    }

    const assistantMessage = {
      role: 'assistant',
      content: currentContent || null,
      tool_calls: collectedToolCalls.map((tc, i) => ({
        id: tc.id || `tc_${Date.now()}_${i}`,
        type: tc.type || 'function',
        function: { name: tc.function?.name || '', arguments: tc.function?.arguments || '{}' }
      }))
    };
    currentMessages.push(assistantMessage);

    for (const tc of collectedToolCalls) {
      const name = tc.function?.name || tc.name;
      const args = parseToolCallArguments(tc);
      const id = tc.id || `tc_${Date.now()}`;

      onChunk({ type: 'tool_start', name, args });

      let result;
      try {
        result = await executeTool(name, args, sender);
      } catch (e) {
        result = { error: e.message };
      }

      onChunk({ type: 'tool_end', name, result });

      currentMessages.push({
        role: 'tool',
        tool_call_id: id,
        content: typeof result === 'string' ? result : JSON.stringify(result)
      });
    }

    iteration++;
  }

  const finalMessage = {
    role: 'assistant',
    content: fullResponse
  };

  return finalMessage;
}

export { runChat, parseToolCallArguments };
